Я получаю сообщение об ошибке в коде на стороне клиента о соединение сброшено узлом, когда я вызываю функцию Отправить из клиента --> сервера. Я посмотрел это в Интернете, но я не совсем понимаю, может ли кто-нибудь объяснить, что вызывает эту ошибку и почему?
Это код клиентского сокета. Я заставил его принимать сервер на 127.0.0.1.
#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <errno.h>
#define SERVER_PORT 9002
#define BUFSIZE 4096
#define SOCKETERROR (-1)
#define SERVER_BACKLOG 1
typedef struct sockaddr_in SA_IN;
typedef struct sockaddr SA;
struct sockaddr_in init_socket(const char* address);
void check(int output,const char* msg);
int main(int argc,char** argv){
int number = 0;
int client_socket;
SA_IN client_address;
check((client_socket = socket(AF_INET,SOCK_STREAM,0)),"[SERVER] : cannot create socket");
client_address = init_socket("127.0.0.1");
check(connect(client_socket,(struct sockaddr*)&client_address,sizeof(client_address)),"[CLIENT]--(connect)--->[SERVER] ");
while(1){
if (send(client_socket,&number,sizeof(number),0),"[CLIENT]-------->[SERVER] " > 0){
number++;
if (number == 100) break;
printf("[CLIENT] : %d\n",number);
check(recv(client_socket,&number,sizeof(int),0),"[CLIENT]-------->[SERVER] ");
}
}
close(client_socket);
return 0;
}
struct sockaddr_in init_socket(const char* address){
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(SERVER_PORT);
// server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_addr.s_addr = inet_addr(address);
return server_address;
}
void check(int output,const char* msg){
if (output < 0){
perror(msg);
exit(1);
}
}
Это код серверного сокета. Он принимает клиентов с любого адреса (INADDR_ANY).
#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <errno.h>
#define SERVER_PORT 9002
#define BUFSIZE 4096
#define SOCKETERROR (-1)
#define SERVER_BACKLOG 1
typedef struct sockaddr_in SA_IN;
typedef struct sockaddr SA;
void handle_connection(int client_socket);
struct sockaddr_in init_socket();
void check(int output,const char* msg);
int main(int argc,char** argv){
int number;
int server_socket , client_socket;
SA_IN server_address ,client_address;
check((server_socket = socket(AF_INET,SOCK_STREAM,0)),"[SERVER] : cannot create socket");
server_address = init_socket();
check(bind(server_socket,(SA*)&server_address,sizeof(server_address)),"[SERVER] : binding error");
check((client_socket = listen(server_socket,SERVER_BACKLOG)),"[SERVER] : listen failed");
while(1){
if (recv(client_socket,&number,sizeof(int),0) > 0){
number++;
if (number == 100) break;
printf("[SERVER] : %d\n",number);
check(send(client_socket,&number,sizeof(number),0),"[SERVER]-------->[CLIENT]: ERROR");
}
}
close(server_socket);
return 0;
}
struct sockaddr_in init_socket(){
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(SERVER_PORT);
server_address.sin_addr.s_addr = INADDR_ANY;
return server_address;
}
void check(int output,const char* msg){
if (output < 0){
fprintf(stderr,"%s\n",msg);
exit(1);
}
}
Это означает, что другая сторона закрыла сокет.
Вы неправильно реагируете на конец потока в клиенте, поэтому продолжаете отправлять после того, как сервер отключился, поэтому, когда вы продолжаете отправлять, вы получаете сброс соединения. Решение: правильно реагировать на конец потока, закрывая сокет. Без сомнения, это то, что check()
должен делать, но это не так.
«Соединение, сброшенное узлом» — это именно то, на что это похоже: «Узел» (другая сторона соединения) закрыл соединение.
Обычно вы обнаруживаете это, проверяя, доступен ли сокет для чтения, и когда read
(или recv
) возвращает 0
.
Если вы не обнаружите это таким образом и вместо этого попытаетесь записать в сокет, вы получите ту ошибку, которую вы получаете.
Если вы получите эту ошибку (или обнаружите закрытое соединение другим способом), вам следует закрыть конец соединения.
Конкретная проблема с вашим кодом заключается в том, что ваша функция check
проверяет только ошибки, а не другие условия, которые могут применяться (например, закрытое соединение).
Почти всегда рекомендуется сохранять то, что возвращает read
или recv
, в переменной, которую можно проверить на наличие явных ошибок (-1
), закрытого соединения (0
) или успешно полученных данных (> 0
).
Помните, что TCP — это протокол потоковое. Передаваемые данные представляют собой просто поток байтов. Нет границ сообщения или разделителей. Поэтому часто может случиться так, что одно «сообщение», отправленное через сокет TCP, может быть не получено полностью на другом конце. Когда вы получаете из сокета, вы должны точно знать, сколько нужно получить, и делать это в цикле, пока не получите полное сообщение. Крайне маловероятно в вашем случае, когда вы передаете только
int
, но что-то нужно помнить для будущих программ.