Написание сервера - PullRequest
       2

Написание сервера

2 голосов
/ 25 ноября 2011

Я пытаюсь написать сервер на Java. Я очень мало знаю Java. Я нашел пример использования Selector.

выглядит хорошо, но ведет себя странно. Когда я делаю my_socket_output_stream.writeBytes ("hello world") в клиентском коде, сервер читает это сообщение по одному байту за раз. Разве я не должен получать уведомления только при отправке полного сообщения? Теперь я должен проверить свой буфер после получения каждого байта, чтобы узнать, могу ли я уже работать с ним. Кажется ужасно неэффективным.

Интересно, это из-за селектора или так работают сокеты (я давно их не использовал). Могу ли я заставить их ждать полного сообщения как-нибудь? Кроме того, я могу связать некоторые объекты с каналом? Прямо сейчас все сокеты используют один и тот же буфер. Я уверен, что вы видите, как это проблема ..

Причина, по которой я хочу использовать селектор, заключается в том, что мой сервер будет работать только с HashTable. Несколько потоков просто будут постоянно ждать. И у меня все равно есть только одно ядро. Хотя, может быть, сочетание ThreadPoolExecutor и ConcurrentHashMap будет хорошим выбором? Это наверняка позволило бы мне иметь буфер на сокет ..

Буду признателен за предложения.

Ответы [ 3 ]

1 голос
/ 11 января 2012

Если вы не приобрели некоторый навык в понимании проблем многопоточности и синхронизации, избегайте NIO. Это хорошая вещь, но вы (в настоящее время) недостаточно подготовлены для ее отладки, тем более не в полной мере понимаете и понимаете необходимость ее синхронизации.

Напишите класс Runnable, который оборачивает ServerSocket в цикл while, позволяя циклу блокироваться в методе accept. Затем возьмите этот сокет возврата и создайте поток «обработчик клиента», который будет обрабатывать любые данные, поступившие в NIC.

Этот ресурс даст вам несколько советов по написанию этого более старого, немного более медленного и гораздо более понятного цикла прослушивания сервера. Я ссылался на «среднюю» страницу в статье, так как это листинг кода, но вы можете прочитать всю статью.

При этом используется более старая модель сетевой обработки «один поток для обработки запроса». Это не так уж плохо, но может возникнуть проблема с масштабируемостью.

Альтернатива - совершить глубокое погружение и сделать это с неблокирующим NIO. Это не очень сложно, но для этого нужно, чтобы вы полностью структурировали свой серверный код не так просто. По сути, вы получаете «пулы» рабочих потоков, которые могут выполнять различные задачи, а затем синхронизируете их при передаче данных от рабочего к работнику.

1 голос
/ 25 мая 2012

Я столкнулся с той же проблемой очень давно. Я решил сначала посылать количество байтов сообщения, а затем отправлять само сообщение байтом за байтом. Затем я расширил его построчно.

На стороне отправителя:

// code at sender side
StreamConnectionNotifier service =  (StreamConnectionNotifier) Connector.open( url );
//System.out.println("opened");
StreamConnection con = (StreamConnection) service.acceptAndOpen();
OutputStream outputStream = con.openOutputStream();


// file to send
Scanner in = new Scanner(inFile);

//just count lines
String s=null;
int countLines=0;
while(in.hasNext()) {
    s=in.nextLine();
    countLines++;
}

//send num of lines
outputStream.write(Integer.toHexString(countLines).getBytes());
try{Thread.sleep(100);} catch(InterruptedException e){}

//send lines
in = new Scanner(inFile);
for(int i=0; i<countLines; i++) {
    s=in.nextLine()+"\n";
    outputStream.write(s.getBytes());
    Thread.sleep(100);
}

На стороне получателя:

// code at receiver side
byte buffer[] = new byte[80];
int bytes_read = inputStream.read( buffer );
String received = new String(buffer, 0, bytes_read);
try{Thread.sleep(100);} catch(InterruptedException e){}
int receiveLines = Integer.parseInt(received);

PrintWriter out = new PrintWriter(new FileOutputStream("received.txt"));

for(int i=0; i<receiveLines; i++) {
  bytes_read = inputStream.read( buffer );
  received = new String(buffer, 0, bytes_read);
  out.println(received);    
  Thread.sleep(100);
} 

Надеюсь, это поможет:)

0 голосов
/ 11 января 2012

Разве я не должен получать уведомления только при отправке полного сообщения?

Нет. Без указания того, как сообщения должны быть отделены друг от друга, API может выдавать вам только один байт за раз (или все доступные байты). Самым простым способом разделения строк было бы использование java.io.PrintStream на стороне, которая отправляет сообщение, и java.io.BufferedReader на стороне, которая получает, например:

// code that sends strings
OutputStream out = ...; // get the output stream from the socket
PrintStream sender = new PrintStream(out);
sender.println("Hello, world.");

// code that receives strings
InputStream in = ...; // get the input stream from the socket
BufferedReader receiver = new BufferedReader(new InputStreamReader(in));
String message = receiver.readLine(); // reads "Hello, world."
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...