首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C语言 >

c多线程服务器端怎么获得客户端关闭信息

2012-03-16 
c多线程服务器端如何获得客户端关闭信息?多线程服务器端代码运行已经正常,来一个客户端,主线程就开一个线

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 ”了


热点排行