c多线程服务器端如何获得客户端关闭信息?
多线程服务器端代码运行已经正常,来一个客户端,主线程就开一个线程给他,将客户端发来的信息发回去,客户端代码我想就不用发了吧。现在我想加个功能,当有客户端退出的时候,服务器端探测到,这样就可以打印出谁退出了。本来想用pthread_join(threadd[i],NULL)这个挂起函数,但是总不成功,好像select函数可以做到,苦于不知道怎么用,哪位高手指点一二,谢谢了。
我中间加了不少检测的printf()代码,就是为当时找错方便用的,希望不要影响您阅读。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netdb.h>
#include <signal.h>
#include <pthread.h>
#define PORT 29004
#define BACKLOG 10
void * echoclient(void *point);
int g_number;
int main()
{
pthread_t threadd[100];
int listenfd,newfd,n,n2,jo,i=0;
int *point;
int opt;
struct sockaddr_in my_addr;
struct sockaddr_in their_addr;
int sin_size;
listenfd = socket(AF_INET,SOCK_STREAM,0);
if(listenfd == -1) //创建套接字
{
perror( "socket 没有成功 ");
exit(1);
}
printf( "socket is [%d]\n ", listenfd);
bzero(&(my_addr),sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(PORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
opt=1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(int));
n = bind(listenfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));
if(n == -1)//绑定地址
{
printf( "error socket is [%d]\n ", listenfd);
perror( "bind 没有成功 ");
exit(1);
}
n = listen(listenfd,BACKLOG);
if(n == -1) //宣告可接受连接
{
perror( "listen没有成功 ");
exit(1);
}
for(;;)
{
sin_size = sizeof(struct sockaddr_in);
newfd = accept(listenfd,(struct sockaddr*)&their_addr,&sin_size);
if(newfd == -1)
{
if(errno == EINTR)
{
continue;
}
perror( "accept没有成功 ");
continue;
}
printf( "server: got connection from %s \n ", inet_ntoa(their_addr.sin_addr));
g_number++;
point = malloc(sizeof(int));
*point = newfd;
n = pthread_create(&threadd[i], NULL, (void *)&echoclient, point);
i++;
////printf( "创建线程以后往后执行,看看n是多少 %d \n ",n);
if(n == 0)
{
n = send(newfd, "您已经和服务器连接了\n ",19,0);
printf( "the data of send is [%d]\n ", n);
if(n == -1) //数据传输
{
perror( "send没有成功 ");
}
printf( "第 %d 个线程到来了\n ",g_number);
}
}
}
void * echoclient(void *point) //子线程执行循环
{
int n,sockfd,i;
char buf[2048];
sockfd = *(int *)point;
for(;;)
{
memset(buf, 0, sizeof(buf));
n = read(sockfd, buf, sizeof(buf));
if(n <= 0)
{
break;
}
printf( "服务器接受的消息为[%s]\n ", buf);
write(sockfd, buf, n);
printf( "服务器发送的消息为[%s]\n ", buf);
}
close(sockfd);
}
[解决办法]
select可以设置超时,当客户端在设定时间内没有数据返回,则表示断开连接,另外,我想你所说的客户端连接断开应该是意外断开的情况吧,tcp连接时正常断开在服务器端可以接收到断开的信息的。
关于select的使用,网络上有很多文章
http://blog.csdn.net/civet148/archive/2006/06/01/766970.aspx
这个可以参考
再有就是设定通信的高层协议,对于客户端在一定时间内没有响应,则认为客户端已经断开。
[解决办法]
单就你上面的程序逻辑我觉得还用不到select,你只在一个描述符里进行循环的读写。
在TCP连接一端关闭时,在另一端的套接口上等待读的read函数会返回0的。
如果你的程序别的地方没有错的话,你把echoclient函数中的第8行
if(n <= 0)
{
break;
}
改成
if(n < 0)
{
break;
}
elseif(n = 0)
{
printf( "connect broken \n ");
close(sockfd);
return -1;
}
……
具体怎么写你可以具体情况具体对待,关键是把返回0的情况单独提出来判断一下。当客户端宕了也好,关闭了套节口也好,应该可以看见关闭信息“connect broken ”了