2015-06-14 2 views
0

Я пишу сервер-клиентскую программу на C. Клиент отправляет команду серверу в виде 5 байтов: первый байт - это операция, а следующие 4 байта являются ключом для выполнения операции.C: странное поведение между клиентом и сервером

Сервер выглядит примерно так:

int nowread, key; 
while(1) 
{ 
    char buffer[1024]; 
    int alreadyread = 0; 
    do 
    { 
     nowread = read(socket,buffer+alreadyread,5-alreadyread); 
     alreadyread += nowread; 
    } 
    while((nowread > 0) && (5-alreadyread > 0)); 

    if(nowread == -1 || nowread == 0) 
    { 
     printf("Error reading from client socket\n"); 
     exit(1); 
    } 

    key = (((int)buffer[1])<<24 | ((int)buffer[2])<< 16 | ((int)buffer[3]) << 8 | ((int)buffer[4]) << 0); 

    printf("%d, key from server \n",key); // just for debugging 


//DO COMMAND 

Я тестировал программу, имея клиента отправить 10 команд:

op: 1, num: 645110 
op: 2, num: 419811 
op: 0, num: 115300 
op: 2, num: 792023 
op: 2, num: 146624 
op: 1, num: 842346 
op: 1, num: 450778 
op: 0, num: 550046 
op: 1, num: 284186 
op: 2, num: 691858 

И я получаю от сервера:

-10, key from server 
-29, key from server 
-15772, key from server 
-41, key from server 
-64, key from server 
-9622, key from server 
-38, key from server 
-98, key from server 
284186, key from server 
-110, key from server 

Как вы можете видеть, только один ключ соответствует, что очень странно (либо они должны совпадать, либо нет) , Я на 100% уверен, что это серверный сервер, а не проблема с клиентом. Кто-нибудь знает, что может быть причиной этого?

Заранее спасибо.

EDIT: Это код, который посылает данные

uint32_t net_num = htonl(num); 
    int nsent = 0; 
    while (nsent < 4) 
    { 
     rc = write(sockfd,&net_num + nsent, 4 - nsent); 
     if (rc <= 0) 
     { 
      printf("error! write() failed: %s\n", strerror(errno)); 
      break; 
     } 

     nsent += rc; 
    } 

    if (rc <= 0) 
     break; 
+1

Как вы * отправить * данные? –

+0

Очень важно, чтобы вы отображали код, который отправляет данные. Возможно, вы сталкиваетесь с проблемами, связанными с контентом, или с другими незначительными проблемами. –

+0

Я отредактировал его. –

ответ

1

Тип char подписан на вашей системе, поэтому значения байтов по знаку при преобразовании их в int, как вы вычисляя key Значение на стороне сервера. Явные приведения не нужны, и результат будет идентичным без них.

Вы должны сделать buffer массив из unsigned char:

unsigned char buffer[1024]; 

Клиентский код ошибочен тоже, он работает только тогда, когда nsent является 0. Если по какой-то невероятной причине write пишет только между 1 и 3 байтами, вы будете пытаться передавать байты из памяти за пределами конца переменной net_num, ссылаясь на неопределенное поведение:

записи (sockfd, & net_num + nsent, 4 - nsent);

Вы должны сделать это вместо того, чтобы:

write(sockfd, (unsigned char*)&net_num + nsent, 4 - nsent); 

или лучше, для обеспечения соответствия с кодом сервера:

char buffer[5]; 
ssize_t rc, nsent; 

buffer[0] = code; 
buffer[1] = (num >> 24) & 255; 
buffer[2] = (num >> 16) & 255; 
buffer[3] = (num >> 8) & 255; 
buffer[4] = (num >> 0) & 255; 

for (nsent = 0; nsent < 5; nsent += rc) { 
    rc = write(sockfd, buffer + nsent, 5 - nsent); 
    if (rc <= 0) { 
     printf("error! write() failed: %s\n", strerror(errno)); 
     break; 
    } 
} 

if (rc <= 0) 
    break; 
1

Вы обрабатываете буфер в неправильном направлении. Вам также необходимо преобразовать его из сетевых байтов. ntohl() делает это.

Как это:

uint32_t key; 
uint32_t result; 

key = (uint32_t)((buffer [ 1 ] << 0) | 
        (buffer [ 2 ] << 8) | 
        (buffer [ 3 ] << 16) | 
        (buffer [ 4 ] << 24)); 

result = ntohl (key); 
+0

Я думаю, вы ошибаетесь: OP ** делает ** обрабатывать буфер в сети, чтобы получить значение напрямую. По его собственным данным, одна передача правильная: '284186, ключ от сервера', который не будет иметь места, если порядок байтов был ошибочным. Ошибки исходят от использования массива 'char' вместо' unsigned char'. У вашего метода есть та же проблема, плюс он не работает на платформе большого конца: вы должны прочитать «ключ» следующим образом: 'key = * (uint32_t *) (buf + 1);', но адрес должен был бы быть правильно выровнен. Метод OPs намного проще. Он должен использовать его и в клиентском коде для согласованности. – chqrlie

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