struct?sockaddr_in?saddr;?
struct?sockaddr_in?caddr;?
struct?client?
{?
int?sock;?
struct?client?*next;?
};?
struct?client?*init_list()//創建客戶端隊列頭,為了讓客戶端“群聊”?
{?
struct?client?*head?=?malloc(sizeof(struct?client));?
head->next?=?NULL;?
return?head;?
}?
int?add_node(struct?client*head,int?new_sockfd)?
{?
struct?client?*new?=?malloc(sizeof(struct?client));?
struct?client?*p?=?head;?
new->sock?=?new_sockfd;?
new->next?=?NULL;?
while(p->next!=NULL)?
{?
p?=?p->next;?
}?
p->next?=?new;?
new->next?=?NULL;?
return?0;?
}?
int?del_node(struct?client*head,int?sockfd)?
{?
struct?client?*q?=?head;?
struct?client?*p?=?q->next;?
while(p->sock?!=sockfd)?
{?
if(p->next?!=NULL)?
{?
p?=?p->next;?
q?=?q->next;?
}?
else?if(p->next?==?NULL)//cannot?find?the?sockfd?
{?
printf("can?not?find?sockfd?to?del\n");?
return?-1;?
}?
}?
q->next?=?p->next;?
free(p);?
return?0;?
}?
int?broadcast_client(struct?client*head,int?sockfd,char?*buf)?
{?
struct?client?*p?=?head->next;?
while(p!=NULL)?
{?
if(p->sock?!=?sockfd)?
{?
write(p->sock,buf,50);?
}?
else?if(p->sock?==?sockfd)?
{?
p?=?p->next;?
continue;?
}?
p?=?p->next;?
}?
return?0;?
}?
void*?thread(void*?arg)?
{?
pthread_detach(pthread_self());?//設置該線程為分離狀態,不需要主線程回收其系統資源。?
char?buf[50];?
char?ipbuf[50];?
bzero(ipbuf,50);?
bzero(buf,50);?
int?port;?
int?sockfd?=?*((int*)arg);?
while(1)?//循環接收客戶端發來的信息?
{?
read(sockfd,buf,50);?
if(strcmp(buf,"quit")==0)//當客戶端發來的信息為?quit,則退出線程,並刪除該結點?
{?
del_node(head,sockfd);?
pthread_exit(NULL);?
}?
inet_ntop(AF_INET,(void*)&caddr.sin_addr.s_addr,ipbuf,50);?//把客戶端的ip信息放到ipbuf中?
port?=?ntohs(caddr.sin_port);//把客戶端的端口號放到變量port中?
printf("read?from?ip:%s,port:%hu\n",ipbuf,port);?
printf("message:%s\n",buf);?
broadcast_client(head,sockfd,buf);?//把壹個客戶端發來的信息轉發給其他客戶端?
bzero(buf,50);?
}?
}?
int?main()?
{?
int?sockfd,new_sockfd;?
int?size,ret;?
pthread_t?tid;?
size?=?sizeof(struct?sockaddr_in);?
head?=?init_list();?
bzero(&saddr,size);?
saddr.sin_family?=?AF_INET;?//綁定協議域為?IPv4?
saddr.sin_port?=?htons(7777);//綁定端口號為7777?
saddr.sin_addr.s_addr?=?htonl(INADDR_ANY);?//綁定ip地址為本機的壹個隨機IP?
sockfd?=?socket(AF_INET,SOCK_STREAM,0);?//創建socket套接字?
ret?=?bind(sockfd,(struct?sockaddr*)&saddr,size);?//socket套接字和sockaddr_in結構體綁定在壹起,賦予socket屬性?
listen(sockfd,5);//開始監聽有沒有客戶端連接?
while(1)//循環監聽有沒有客戶端連接進來,就像壹個接待人員等待客人,有客人來了就服務他?
{?
new_sockfd?=?accept(sockfd,(struct?sockaddr*)&caddr,&size);?//等待客戶端連接,並返回該客戶端的描述符?
add_node(head,new_sockfd);//若有客戶端連接,則把該客戶端加入到客戶端隊列中?
pthread_create(&tid,NULL,thread,(void*)&new_sockfd);//創建壹個線程服務新連接進來的客戶端?
}?
pthread_exit(NULL);?
return?0;?
}?
接下來是客戶端:
[cpp]?view?plain?copy
//TCP客戶端?
#include"myhead.h"?
void*?thread(void*?arg)?//讀取從服務器轉發過來的信息,這些信息是其他客戶端發到服務器上,服務器再轉發過來的?
{?
char?buf[50];?
int?sockfd?=?*((int*)arg);?
while(1)?//循環等待服務器有沒有信息發過來,有就打印出來,沒就阻塞等待?
{?
read(sockfd,buf,50);?
printf("%s\n",buf);?
}?
}?
int?main()?
{?
int?sockfd;?
int?size;?
char?buf[50]={0};?
pthread_t?tid;?
struct?sockaddr_in?saddr;?
size?=?sizeof(saddr);?
bzero(&saddr,size);?
saddr.sin_family?=?AF_INET;?
saddr.sin_port?=?htons(7777);?
saddr.sin_addr.s_addr?=?inet_addr("192.168.152.128");//這裏的IP是服務端的IP?
sockfd?=?socket(AF_INET,SOCK_STREAM,0);?
connect(sockfd,(struct?sockaddr*)&saddr,size);//連接服務端?
pthread_create(&tid,NULL,thread,(void*)&sockfd);?//連接成功後,創建壹條線程用於循環讀取服務端發來的信息?
while(1)?//主線程用於給服務端發信息。?
{?
scanf("%s",buf);?
write(sockfd,buf,50);?
bzero(buf,50);?
}?
return?0;?
}