2014-08-29 3 views
0

Я пытаюсь читать и писать в сокет, используя сетевое программирование linux в C. Я делаю успешные вызовы «писать» и «читать» в клиентских и серверных программах соответственно.Ошибка сокета в C с использованием функций чтения и записи

Часть, с которой я с трудом понимаю, заключается в том, что на моей клиентской программе я петлю и вызываю запись 5 раз, на сервере, я петлю и вызываю чтение 5 раз.

Это ожидаемый результат:

MSG: I got your message MSG: I got your message MSG: I got your message MSG: I got your message MSG: I got your message 

Это фактический выход:

MSG: I got your messageI got your messageMSG: I got your messageI got your messageMSG: I got your messageMSG: MSG: 

Как вы можете видеть ожидаемый результат и фактический выход различны. Похоже, клиент может позвонить «написать» дважды, прежде чем он будет отправлен.

Это то, что у меня есть для кода клиента

for(int i=0;i<5;i++) 
{ 
    int n = write(ssocket.socketFileDescriptor,"I got your message",18); 
    cout<<n<<" number of bytes written."<<endl; 
    if (n < 0) socketError("ERROR writing to socket"); 
} 

Это код сервера:

void* run(void* arg) 
{ 
    ServerSocket* ss = (ServerSocket*)arg; 
    //while(true) 
    for(int i=0;i<5;i++) 
    { 
     char buffer[256]; 
     bzero(buffer,256); 
     int n = read(ss->newsockfd,buffer,256); 
     printf("MSG: %s",buffer); 
    } 
    close(ss->newsockfd); 
} 

Это дополнение к вопросу, ниже которого находится вне даты в данный момент.

Мне не хватает звонка на флеш или что-то еще?

Simulate Java's Thread class in C++

+1

Вы считаете, что TCP может передавать сообщения размером более одного байта. Он не может - это протокол байта/октета STREAMING и не знает границ сообщений выше одного байта. Если вы хотите передавать более крупные и более сложные сообщения, вам нужен протокол поверх TCP. Есть бесконечные оверки этого вопроса - так много, что меня не беспокоит, чтобы выглядеть :) –

+0

Если вы используете сокеты TCP, то все отправленное объединяется в один поток, и когда он читается, вы получаете то, что доступно в этот момент (до размера буфера). Вам необходимо вставить свои собственные границы сообщений и проанализировать поток в ресивере. – molbdnilo

+0

Итак, я открыл wirehark и подтвердил, что каждый вызов «write» фактически создал собственный пакет. Это означает, что чтение является тем, где оно удваивается. Вот где я увидел «чтение», и я сказал в своем коде, чтобы прочитать 256 байтов. – Matthew

ответ

2

Ваш клиент и сервер просто не скоординированы. Клиент записывает сообщение 5 раз как можно быстрее, и сервер читает пять раз быстрее, чем он может. В вашем примере вывода, очевидно, при первом вызове read() клиент отправил сообщение дважды, а при втором вызове read() его отправили еще два раза. Вы получите read() до 256 символов, и каждый раз, когда вы его вызываете, он просто попытается прочитать все, что находится в буфере. Если к этому времени клиент отправил несколько сообщений, read() просто возьмет все.

Обычно вам требуется какой-то тип синхронизации, например. после того, как вы отправите одно сообщение, ваш клиент ждет, когда сервер отправит "OK" или что-то подобное, прежде чем отправит второе сообщение. Кроме того, вы можете использовать какой-то маркер конца сообщения (например, новую строку), чтобы сервер мог отличить их, если у вас очень простой формат связи.

+0

Или просто добавьте буферизацию с обеих сторон (сервер и клиент). –

+0

Да! Я хотел бы добавить буферизацию, но я точно не знаю, как это сделать. Я пытаюсь создать систему, похожую на Java, и все, что встроено в BufferedFileReader или что-то еще ... Как вы делаете буферизацию? Кроме того, скажите, что я хочу отправить более 256 символов без ответа? Как мне это сделать? Я предполагаю, что этот сокет использует TCP, поэтому мне не нужно признавать в любом случае, правда? – Matthew

+0

@Matthew: Лучше всего использовать одну из многих сторонних сетевых библиотек. Реализация буферизации не так уж и трудна, но это не совсем тривиально. Вы можете реализовать версию этого бедного человека с помощью 'read()' по одному символу за раз, пока не нажмете символ конца строки для приема строк неизвестной длины. Использование системного вызова для одиночных символов относительно неэффективно, но если вы не пишете сервер с большими объемами, сеть, вероятно, будет узким местом. –

Смежные вопросы