我有一个使用C语言的套接字的多线程客户端 - 服务器架构。
Client.c
sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr=inet_addr("127.0.0.1");
address.sin_port = 9734;
len = sizeof(address);
result = connect(sockfd, (struct sockaddr *)&address, len);
if(result==-1) {
perror("oops: client1");
return 1;
}
while(1) {
printf("Enter a string: ");
scanf("%s", str);
if(strcmp(str,"exit") == 0) close(sockfd); //At this point server terminates
write(sockfd, str, 100);
read(sockfd, str, 100);
printf("from server = %s\n", str);
}
Server.c
int main() {
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address, client_address;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
server_address.sin_port = 9734;
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
listen(server_sockfd, 100);
while( (client_sockfd = accept(server_sockfd,(struct sockaddr*)&client_address, &client_len)) ) {
// client_len = sizeof(client_address);
// client_sockfd = accept(server_sockfd,(struct sockaddr*)&client_address, &client_len);
pthread_t sniffer_thread;
int *new_sock = malloc(sizeof(int *));
*new_sock = client_sockfd;
if( pthread_create( &sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0)
{
perror("could not create thread");
return 1;
}
printf("New thread assigned\n");
}
// close(server_sockfd);
}
void *connection_handler(void *sock) {
int client_sockfd = *(int *)sock;
char str[100];
while(1) { // If I remove this while loop, it works fine
printf("server waiting\n");
read(client_sockfd, str, 100);
write(client_sockfd, str, 100);
}
}
基本上,我们的想法是让服务器连续运行,新客户端可以根据需要连接和断开连接。
问题是,只要客户端被中断了Ctrl+C
或“退出”消息,客户端就会终止,但服务器也会终止。服务器不应该终止,而是监听大多数传入的套接字请求。
有人可以就我究竟做错了什么提供方向吗?我不希望fork新进程或使用select()
。它必须是一个多线程解决方案。
更新
我对代码进行了一些更改,主要是添加更多错误检查等。如果我在server.c
中的线程连接处理程序中删除了while循环,则服务器不会终止客户端,这就是我想要的。但我不想删除while循环,因为这意味着服务器和客户端只能在套接字自动关闭之前发送一条消息。
答案 0 :(得分:1)
您似乎认为客户端套接字(由accept()
返回的套接字)与服务器的原始套接字相同,即您正在侦听的套接字。
事实并非如此,因为accept()
创建了一个专用于该客户端并连接到客户端的新套接字。一旦客户离开,这个套接字没有用,它应该关闭。这不会影响您的服务器接受更多连接的能力。
答案 1 :(得分:1)
服务器崩溃,因为连接处理程序无法识别客户端断开连接,并尝试写入另一端关闭的套接字。这会产生SIGPIPE
,默认操作是终止整个过程。
一个简单的解决方法是检查read
的返回值,如果是0
,则从线程返回而不写入。