#include int sock; /* POSIX用int 来描述socket */
/* 多线程 TCP chat 服务器*/
#define MAX_USERS 30
/* 在线用户表,用下标表示对应的socket, online_user[8] =1 ,表示socket fd =8的socket 在线,=0表示下线*/
char online_user[MAX_USERS];
/* 用来保护在线用户表 online_user*/
pthread_mutex_t user_lock;
void exit_handler(int sig)
{
close(sock);
pthread_mutex_destroy(&user_lock);
exit(0);
}
void * thread_fn(void *arg)
{
char buffer[1024];
int len,fd;
int client_sock = (int)arg;
while(1)
{
/* 接收客户端数据*/
len = recv(client_sock,buffer,sizeof(buffer)-1,0);
if(len <=0)
{/* 通常是客户端已经关闭,从在线用户表把当前sock 清掉*/
perror("recv");
pthread_mutex_lock(&user_lock);
online_user[client_sock] =0;
pthread_mutex_unlock(&user_lock);
break;
}
buffer[len] =0;
fprintf(stdout,"client:%s\n",buffer);
/* 把数据轮播到其它客户端*/
for(fd=0; fd< MAX_USERS ;fd++)
{
if((online_user[fd] == 0) || (fd == client_sock))
continue;
len = send(fd,buffer,len,0);
if(len<= 0)
{
perror("send");
pthread_mutex_lock(&user_lock);
online_user[client_sock] =0;
pthread_mutex_unlock(&user_lock);
break;
}
}
}
close(client_sock);
}
int main(int argc,char * argv[])
{
unsigned short port = 9000;
socklen_t addrlen;
struct sockaddr_in local_addr,client_addr;
int client_sock,len,i;
pthread_t th;
const char * welcome_msg = "Welcom to Chat Server ,ver 1.0";
signal(SIGINT,exit_handler);
if(argc>1)
{
port = (unsigned short )atoi(argv[1]);
}
/* ------------第一步:创建socket ----------------*/
sock = socket(PF_INET,SOCK_STREAM,0); /* ipv4,TCP,任意协议 */
if(sock == -1)
{
perror("socket");
exit(-1);
}
fprintf(stdout,"TCP char Server ,listen on %d,pit %d\n",port,getpid());
/* ----------------第二步:绑定端口和网卡----------------------*/
/* struct socketaddr_in 来指明这个SOCKET绑定在本地的哪一个的端口和哪一块网卡*/
memset((void *)&local_addr,0,sizeof(local_addr));
local_addr.sin_family = AF_INET ; /* ip v4 */
local_addr.sin_port = htons(port); /* 端口号,要用网络序*/
/* 可以取值 INADDR_ANY 表示这个socket可以这一台机器所有网卡上进行通信*/
/* 如果本机一个某一个网卡的IP地址,表示只在这一块网卡进行通信*/
local_addr.sin_addr.s_addr = INADDR_ANY; /* INADDR_ANY = 0x0 */
{
int val = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof (val));
}
if(bind(sock,(struct sockaddr *)&local_addr,sizeof(local_addr)) == -1)
{
perror("bind");
close(sock);
exit(-2);
}
/* ----------第三步:通知内核的PS开始侦听客户端请求-------------*/
if(listen(sock,20) == -1)
{
perror("listen");
close(sock);
exit(-3);
}
/* 清空在线用户表,初始化锁*/
for(i=0 ; i < MAX_USERS ;i++)
online_user[i] =0;
if(pthread_mutex_init(&user_lock,NULL)!=0)
{
perror("mutex_init");
}
/*------ 第四步:接收客户端请求--------------------------*/
while(1)
{
addrlen = sizeof(client_addr);
client_sock = accept(sock,(struct sockaddr *)&client_addr,&addrlen);
if(client_sock == -1)
{
perror("accept");
continue;
}
if(client_sock > MAX_USERS)
{
char * close_msg = "online user too many";
fprintf(stdout,"new socket %d is too big,max user is %d\n",client_sock,MAX_USERS);
send(client_sock,close_msg,strlen(close_msg)+1,0);
close(client_sock);
continue;
}
/* 发送欢迎信息*/
send(client_sock,welcome_msg,strlen(welcome_msg)+1,0);
/* 把新联接的socket加入到在线用户表当中*/
pthread_mutex_lock(&user_lock);
online_user[client_sock] =1;
pthread_mutex_unlock(&user_lock);
fprintf(stdout,"client addr %s,port %d,sock %d\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port),client_sock);
pthread_create(&th,NULL,thread_fn,(void *)client_sock);
}
exit_handler(100);
}
客户端:代码比较简单