socket聊天室(服务端)(多线程)(TCP)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了socket聊天室(服务端)(多线程)(TCP)相关的知识,希望对你有一定的参考价值。

#include<string.h>
#include<signal.h>
#include<stdio.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<netdb.h>
#include<pthread.h>
#include<memory.h>
#include<semaphore.h>
int Thread_num=0,count=0; //定义客户端计数器,写线程计数器
int sockfd;
sem_t sem,sem2;   
pthread_mutex_t tmutex,cmutex;
pthread_attr_t pattr; //定义要创建的线程属性
void ct_thread(char* arg,int acpfd);
char chatct[1024]; //定义聊天缓存
void get_sys_time(char* tbuf)  //函数功能:得到当前系统时间并进行裁剪
{
    long t=time(0);
    char *stime=ctime(&t);
    int i=11;
    tbuf[0]=(;
    for(;i<20;i++)
        tbuf[i-10]=stime[i];
    tbuf[i-11]=);
    tbuf[i-10]=\0;
}
void* do_read(void* arg)    //函数功能:读线程,用于接收客户端发来的信息,保存到缓冲区
{
int acfd=(int)arg; char timeb[13]; // char name[7]; // memset(name,0,sizeof(name)); // read(acfd,name,sizeof(name)); // name[sizeof(name)-1]=‘\0‘; // puts(name); while(1) { int ret; char buf[1024]; memset(buf,0,sizeof(buf)); ret=read(acfd,buf,sizeof(buf)); sem_wait(&sem2); if(ret<0) { perror("do_read errro"); continue; } else if(ret==0) { close(acfd); sem_post(&sem2); printf("a person exit\n"); break; } else { memset(timeb,0,sizeof(timeb)); // strcpy(chatct,name); // puts(chatct); // strcat(chatct,":"); // puts(chatct); get_sys_time(timeb); strcpy(chatct,buf); strcat(chatct,timeb); // puts(chatct); // printf("do_read %lu\n",pthread_self()); sem_post(&sem); } // puts(chatct); } return (void*)0; } void* do_write(void* arg) //函数功能:写线程,用于将缓冲区的数据发送到连接上来的每个客户端,当所有客户端接收到消息后,清空缓冲区。 { int fd=(int)arg; while(1) { sem_wait(&sem); if(write(fd,chatct,sizeof(chatct))<0) { Thread_num--; if(count==Thread_num) { memset(chatct,0,sizeof(chatct)); pthread_mutex_lock(&cmutex); count=0; pthread_mutex_unlock(&cmutex); sem_post(&sem2); } else if(count<Thread_num) { sem_post(&sem); } close(fd); break; } else { pthread_mutex_lock(&cmutex); count++; pthread_mutex_unlock(&cmutex); } if(count<Thread_num) { sem_post(&sem); usleep(1); } else if(count==Thread_num) { memset(chatct,0,sizeof(chatct)); pthread_mutex_lock(&cmutex); count=0; pthread_mutex_unlock(&cmutex); sem_post(&sem2); } } return (void*)0; } void do_thread(int acpfd) //函数功能:对于每个连接上来的客户端 创建一个读线程,一个写线程 { // char* start="------------------welcome my chatroom--------------------\n"; // write(acpfd,start,strlen(start)); pthread_mutex_lock(&cmutex); Thread_num++; //每创建一个 线程个数计数加1 pthread_mutex_unlock(&cmutex); ct_thread("read",acpfd); ct_thread("write",acpfd); } void ct_thread(char* arg,int acpfd) //函数功能,根据传参不同,创建不同类型的函数。 { pthread_t pt; /* if(!strcmp(arg,"create")) { if(pthread_create(&pt,&pattr,thread_ct,(void*)acpfd)<0) { perror("thread creat error"); exit(1); } } */ //以分离方式创建线程可避免资源无法回收 if(!strcmp(arg,"read")) { if(pthread_create(&pt,&pattr,do_read,(void*)acpfd)<0) { perror("thread creat error"); exit(1); } } else if(!strcmp(arg,"write")) { if(pthread_create(&pt,&pattr,do_write,(void*)acpfd)<0) { perror("thread creat error"); exit(1); } } } void mysighand(int signo) //函数功能:当程序结束,处理返回的信号,释放资源 { if(signo==SIGINT) { printf("server close!\n"); close(sockfd); sem_destroy(&sem); sem_destroy(&sem2); pthread_mutex_destroy(&cmutex); pthread_mutex_destroy(&tmutex); pthread_attr_destroy(&pattr); exit(1); } } int main(int argc,char* argv[]) { if(argc<2) { perror("argc error"); exit(1); } if(signal(SIGINT,mysighand)==SIG_ERR) //登记信号处理函数 { perror("signal error"); exit(1); }
/* 1 初始化 sem_init(
&sem,0,0); sem_init(&sem2,0,1); pthread_mutex_init(&tmutex,NULL); pthread_mutex_init(&cmutex,NULL); pthread_attr_init(&pattr);
*/
 
if(pthread_attr_setdetachstate(&pattr,PTHREAD_CREATE_DETACHED)<0) //设置分离属性 { perror("setdetached error"); exit(1); } memset(chatct,0,sizeof(chatct)); //初始化缓存区 sockfd=socket(AF_INET,SOCK_STREAM,0);//以TCP方式创建socket if(sockfd<0) { perror("sockfd error"); exit(1); } struct sockaddr_in ser; ser.sin_family=AF_INET;        //IP类型:IPV4 ser.sin_port=htons(atoi(argv[1])); //主机字节序转换成网络字节序 ser.sin_addr.s_addr=INADDR_ANY;  //主机所有可访问IP  if(bind(sockfd,(struct sockaddr*)&ser,sizeof(ser))<0) //socket和IP绑定 { perror("bind error"); exit(1); } if(listen(sockfd,10)<0) //进行监听等待客户端连接 { perror("listen error"); exit(1); } while(1) { int acpfd; if((acpfd=accept(sockfd,NULL,NULL))<0) //处理每个连接上来的客户端,如果无客户端连接,则阻塞 break; else { do_thread(acpfd); //执行处理连接函数 } } return 0; }

本服务端的主要思想:

为每一个连接上来的客户端创建一个读线程和写线程(分离状态启动的线程,线程进行自我资源回收),服务端和客户端的通信实际就是多读者多写者的模型(利用信号量和客户端计数器,线程计数器,实现线程的同步和互斥)

不同点在于 当客户端断开连接后,服务端应当及时改变客户端计数器,并进行逻辑处理。

服务端运行在云服务器上,客户端可以用QT 或者android 等来实现。

 

不足点:

仅仅是匿名聊天。功能较简单。只是显示聊天内容和数据发送的时间

优点:

可以支持大量客户端同时进行连接。并且在网络速度不健康的情况下数据不会出错(非网络在信道传递时的错误

以上是关于socket聊天室(服务端)(多线程)(TCP)的主要内容,如果未能解决你的问题,请参考以下文章

多线程实现tcp聊天服务器

聊天程序(基于SocketThread)

1500行代码!拥有自己的聊天室------ socket聊天室实现(GUI,线程,TCP)

多线程+socket实现多人聊天室

Linux-TCP编程流程-Socket编程-单线程实现TCP客户端和服务端交互-多进程实现TCP客户端和服务端交互

Java编程实例-tcp聊天室代码实现