Intereting Posts
Перестройте массив, чтобы быть оптимальным по сравнению с другим массивом Существуют ли какие-либо проблемы при использовании чистых C (неclassифицированных) функций в приложении C ++? Является ли структура с одним членом одинаковой производительностью как тип члена? Каков самый переносимый способ получить / установить старший бит целого числа в GNU C Сортировка по блокам элементов с помощью std :: sort () Удалить узел из связанного списка с определенным значением печать заголовка wav в c Как разные строки имеют один и тот же адрес Почему __sync_add_and_fetch работает для 64-битной переменной в 32-битной системе? C: Как я могу использовать единый массив указателей функций для функций с переменными параметрами? Как уменьшить заполнение секции ELF? использование указателей для отображения содержимого массива Запуск плагинов в песочнице Как освободить двумерный массив, используя malloc Есть ли REPL для программирования на C?

Сокеты клиента / сервера в c

В настоящее время я пытаюсь понять, как использовать сокеты, чтобы сделать клиент / серверную программу на C. Я читал различные учебники по Интернету, чтобы попытаться создать небольшой сервер эха, который может работать с несколькими клиентами одновременно. Всякий раз, когда клиент отправляет серверу сообщение, сервер должен эхо вернуться к клиенту. Созданный мной код представляет собой комбинацию из учебника из лекции в школе (в котором объясняется, как создать клиента и сервера), а также пример, который я нашел здесь в stackoverflow (который показал, как заставить функции фактически эхо сообщения). Я надеюсь, что кто-то может объяснить мне, чего мне не хватает, чтобы эта программа работала правильно. Вот код клиента:

#include  #include  #include  #include  #include  #include  char buf[80]; struct sockaddr myname; void replyBack(FILE *fp, int sockfd) { char sendline[1000], recvline[1000]; printf("Enter your echo: \n"); while(fgets(sendline,1000,stdin) != NULL) { write(sockfd,sendline,sizeof(sendline)); if(read(sockfd,recvline,1000) == 0) { printf("str_cli: server terminated prematurely"); exit(-1); } fputs(recvline, stdout); } } main() { int sock, adrlen, cnt; sock = socket(AF_UNIX, SOCK_STREAM, 0); if(sock < 0) { printf("client socket failure%d\n", errno); printf("client: "); exit(1); } myname.sa_family = AF_UNIX; strcpy(myname.sa_data, "/tmp/billb"); adrlen = strlen(myname.sa_data) + sizeof(myname.sa_family); if(connect(sock, &myname, adrlen) < 0) { printf("client connect failure %d\n", errno); perror("client: "); exit(1); } replyBack(stdin,sock); exit(0); } 

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

 #include  #include  #include  #include  #include  #include  #include  struct sockaddr myname; char buf[80]; void echo(int sockfd) { ssize_t n; int write_err; char buf[1000]; char * send_start_pos; while(1) { bytes_in = read(sockfd, buf, 1000); if(bytes_in  0) && !(write_err)) { bytes_out = write(sockfd, send_start_pos, bytes_remaining); if(bytes_out < 0) { if(errno == EINTR) continue; write_err = 1; break; } bytes_remaining -= bytes_out; send_start_pos += bytes_out; } if(write_err) break; } } main() { int sock, new_sd, adrlen, cnt; sock = socket(AF_UNIX, SOCK_STREAM, 0); if(sock < 0) { printf("server socket failure %d\n", errno); perror("server: "); exit(1); } myname.sa_family = AF_UNIX; strcpy(myname.sa_data, "/tmp/billb"); adrlen = strlen(myname.sa_data) + sizeof(myname.sa_family); unlink("/tmp/billb"); /*defensive programming */ if(bind(sock, &myname, adrlen) < 0) { printf("server bind failure%d\n", errno); perror("server: "); exit(1); } if(listen(sock, 5) < 0) { printf("server listen failure %d\n", errno); perror("server: "); exit(1); } while(1) { if(new_sd = accept(sock, &myname, &adrlen) < 0) { printf("server accept failure %d\n", errno); perror("server: "); exit(1); } printf("Socket address in server %d is %s, %s\n", getpid(), myname.sa_data, myname.sa_data); if(fork() == 0) { close(sock); echo(new_sd); exit(0); } close(new_sd); } } 

Проблема при запуске программы заключается в том, что клиент принимает сообщение, но затем фактически не отправляет его на сервер, поэтому сервер никогда не сможет повторить его.

Я знаю, что это, вероятно, основной материал, поэтому я ценю ваше терпение и время!

 adrlen = strlen(myname.sa_data) + sizeof(myname.sa_family); 

Это должно быть sizeof myname . Сокеты unix(7) самом деле определены как имеющие sockaddr_un следующим образом:

  #define UNIX_PATH_MAX 108 struct sockaddr_un { sa_family_t sun_family; /* AF_UNIX */ char sun_path[UNIX_PATH_MAX]; /* pathname */ }; 

Вы дали ему 10+4 в качестве размера. Это должно почти сработать – оно не учитывает завершающий байт NUL в конце имени файла, но даже при добавлении + 1 мне было бы лучше, если бы вы проходили точно по размеру объекта, который у вас есть. (Будьте осторожны с strlen(3) на строках. Почти всегда вам нужно + 1 в любом выражении, которое включает strlen(3) . Забавно.)

 while(fgets(sendline,1000,stdin) != NULL) { write(sockfd,sendline,sizeof(sendline)); 

И здесь вы отправляете все 1000 байтов вашего буфера, независимо от содержимого. Пользователь мог ввести один символ или сто, и вы отправляете все 1000 байтов того, что находится по этому адресу.

Ваш метод echo немного; Я бы рекомендовал разделить списание на свою рутину; Расширенное программирование в среде Unix, второе издание ( превосходная книга, ну, стоит найти копию, если вы планируете использовать Unix или Unix-подобные системы) имеет небольшую сладкую рутину, которую мне действительно нравится:

 ssize_t /* Write "n" bytes to a descriptor */ writen(int fd, const void *ptr, size_t n) { size_t nleft; ssize_t nwritten; nleft = n; while (nleft > 0) { if ((nwritten = write(fd, ptr, nleft)) < 0) { if (nleft == n) return(-1); /* error, return -1 */ else break; /* error, return amount written so far */ } else if (nwritten == 0) { break; } nleft -= nwritten; ptr += nwritten; } return(n - nleft); /* return >= 0 */ } 

(См. lib/writen.c в источнике на веб-сайте книги .)

Я на самом деле не пробовал ваш код, поэтому очень возможно, что ни одна из этих проблем не мешает работе вашего программного обеспечения :), если это так, оставьте комментарий, и я присмотрюсь ближе.

Вам не хватает грузовика включений. Я потратил время на сбор ваших программ, и этот gem выделялся из толпы предупреждений

 warning: suggest parentheses around assignment used as truth value 

На этой линии

 if(new_sd = accept(sock, &myname, &adrlen) < 0) { 

Итак, в основном вы проверяете, принимает ли accept что-то меньшее, чем 0, и присваивая это new_sd. Измените эту строку на

 if((new_sd = accept(sock, &myname, &adrlen)) < 0) { 

Бонус : Большая часть того, что сказал @sarnold в его ответе, верна и в конечном итоге сделает вас лучше, чем мой ответ.