#c #function #sockets #unix #networking
#c #функция #сокеты #unix #сеть
Вопрос:
Я попытался создать серверную программу, которая отправляет и получает сообщения от клиента. Я хочу поместить инструкции чтения и записи в функции, потому что я хочу повторно использовать код (затем я должен отправить и получить больше сообщений). Сервер работает корректно, но когда я помещаю инструкции по записи в writeSocket(), программа запускает SIGPIPE, и я не знаю почему. Я пытался также использовать функцию readSocket() (просто скопируйте инструкции по чтению в функцию), но у меня была та же проблема. Не могли бы вы мне помочь, пожалуйста?
Это код моей серверной программы:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <signal.h>
#include <stdlib.h>
#define MAXSIZE 256
int isTerminated(char buffer[], int len);
void writeSocket(int sock, char buffer[]);
int main(){
struct sockaddr_in Local;
struct sockaddr_in Client;
short int port=1745;
char buffer[MAXSIZE];
int sockfd, newsockfd, n, nread, nwrite, len;
int turn_off=0;//Controllare le impostazioni del contatore
sockfd=socket(AF_INET, SOCK_STREAM, 0);
if(sockfd<0){
fprintf(stderr, "Server: Socket creating failed!n");
return -1;
}else
printf("Server: Socket created!n");
memset(amp;Local, 0, sizeof(Local));
Local.sin_family=AF_INET;
Local.sin_addr.s_addr=htonl(INADDR_ANY);
Local.sin_port=htons(port);
if(bind(sockfd, (struct sockaddr*)amp;Local, sizeof(Local))<0){
fprintf(stderr, "Server: Binding socket failed!n");
return -1;
}else
printf("Server: Bind ok!n");
if(listen(sockfd, 10)<0){
fprintf(stderr, "Server: Listen failed!n");
return -1;
}else
printf("Server: Listen ok!n");
while(1){
buffer[0]='';
printf("Server: Waiting for connection...n");
newsockfd=accept(sockfd, (struct sockaddr*)amp;Client, amp;len);
printf("Server: Connection accepted!n");
nread=0;
while((n=read(newsockfd, amp;(buffer[nread]), MAXSIZE))>0){
nread =n;
printf("Server: Ho letto %d caratteri con %d totali!n", n, nread);
if(isTerminated(buffer, nread))//Fine stringa
break;
}
buffer[nread]='';
printf("Ho ricevuto il messaggio %sn", buffer);
if(!strcmp(buffer, "Turn OFF")){
buffer[0]='';
strcpy(buffer, "Counter OFF");
turn_off=1;
}else{
buffer[0]='';
strcpy(buffer, "OK");
}
/*nwrite=0;
buffer[strlen(buffer)]='';
int str_len=strlen(buffer) 1;
while((str_len>nwrite) amp;amp; (n=write(newsockfd, amp;(buffer[nwrite]), str_len-nwrite)>0))
nwrite =n;*/
writeSocket(sockfd, buffer);
close(newsockfd);
if(turn_off)//Spegni il contatore e salva la sessione
break;
}
close(sockfd);
return 0;
}
void writeSocket(int sock, char buffer[]){
buffer[strlen(buffer)]='';
int str_len=strlen(buffer) 1;
int nwrite=0;
int n;
printf("Devo inviare il messaggio: %sn", buffer);
printf("Valore n: %dn", sock);
while((str_len>nwrite) amp;amp; (n=write(sock, amp;(buffer[nwrite]), str_len-nwrite)>0))
nwrite =n;
}
int isTerminated(char buffer[], int len){
int i;
for(i=0; i<=len; i )
if(buffer[i] == '')
return 1;
return 0;
}
Комментарии:
1.
SIGPIPE
при записи означает, что другой конец закрыл соединение.2. Вы не можете использовать
sockfd
для связи; это прослушивающий сокет. Используйте клиентский сокетnewsockfd
.3. Если другой конец сокета закроет соединение, то
read
вернется0
. Вам нужно проверить это.4.
writeSocket
не обрабатывает возврат -1 (указывающий на ошибку) так, как это делает ваш цикл чтения сокета. Кроме того, вам может потребоваться включить повторное использование сокета. Добавьте это перед вашимbind
вызовом:int enable = 1; int ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, amp;enable, sizeof(enable));
5. @CraigEstey ИМХО, использование SO_REUSEADDR — плохая практика, если вам это действительно не нужно (например, многопроцессорный сервер). Обычно вы не хотите привязываться к уже используемому порту. Если он уже используется, возникает проблема.