版权声明:https://blog.csdn.net/qq_39603089/article/details/85327599
客户端:https://blog.csdn.net/qq_39603089/article/details/85328262
下载地址在最下面
使用C/S 模式,参考下图:
服务端系统简单流程图
思路如下:
运行服务端,绑定端口IP
,并开始监听连接。
signal();
函数捕捉退出信号量,用自定义函数处理,函数功能,向所有在线用户发送结束命令,等待2秒后退出。
进入循环阻塞等待用户连接。并使用pv
信号量做用户上限控制。
消费信号量,用户建立连接后等待接收用户昵称。
查找在线用户昵称是否重复,如果重复向用户发送提醒,并是否pv
信号量。
如果不重复,为用户建立线程来监听该用户发送的消息。
线程处理用户消息并为其转发。
用户退出后,断开与用户的连接。并释放pv
信号量。
pv
消耗完时,服务端就会进入阻塞状况,直到用用户退出释放pv
信号量。
当有pv
信号是就循环从用户结构体数组里找可用的结构体资源。
部分代码解释
#define THREAD_NUMBER 30 //最大链接数
struct Users{
char name[50];
pthread_t thread;
char buf[BUFFER_SIZE];
int client_fd;
char address[20];
int login; //0表示这个结构体为被使用 1 表示这个结构体已经有用户使用
}users[THREAD_NUMBER]; // 结构体数组的长度与pv信号量相等。
init_sem(sem_id, THREAD_NUMBER); //有pv资源时就一定可以找到没有使用的结构体
结构体内保存了用户信息
signal(SIGINT, my_func);
signal(SIGQUIT, my_func);
signal(SIGTSTP,my_func);
使用my_func
函数来处理三个退出信号 my_func
实现的功能就是向用户发送退出消息。
sem_p(sem_id);
while(i<THREAD_NUMBER){ //遍历列表
if(users[i].login==0) //找到可用资源 0 表示可用 1 不可用
break;
i++;
if(i==THREAD_NUMBER){ //循环查找
i=0;
}
}
使结构体数组可以循环使用
users[i].client_fd = accept(sockfd,(struct sockaddr*)&client_sockaddr, &sin_size)
等待接收用户连接
recvbytes=recv(users[i].client_fd, users[i].name, BUFFER_SIZE, 0)
接收用户发送来的消息,也就是用户的昵称,用于之后的判断是否重复。
res = pthread_create(&users[i].thread, NULL, thrd_func, (void*)i);
为用户建立线程函数。专门做该用户的发送消息的监听,大多数情况下处于阻塞监听状态。并实现对用户消息的转发。
在线程内部
if ((recvbytes = recv(users[i].client_fd, users[i].buf, BUFFER_SIZE, 0)) <= 0)
………………
strdeal(users[i].buf,users[i].name); //处理消息函数
循环阻塞监听接收信息。成功后处理消息然后发送。
void strdeal(char s[],char se_name[]){
………………
for(i;i<strlen(s);i++){
if(n>2){
buf[j]=s[i];
j++;
}else if(n==2){
if(len==0){
n++;
name[j]='\0';
j=0;
i--;
continue;
}
name[j]=s[i];
j++;
len--;
}else if(n==1){
if(s[i]==':'){
n++;
name[j]='\0';
len = atoi(name);
j=0;
continue;
}
name[j]=s[i];
j++;
}else{
if(s[i]==':'){
n++;
sign[j]='\0';
j=0;
continue;
}
sign[j]=s[i];
j++;
}
}
if(strcmp(sign,"All")==0){
………………//发送给所有在线人
}else{
………………//发送给单个用户
}
}
处理接收后的字符串。
如果是以All::str
开头,则转发给在线的所有用户。str
是用户群发内容
如果是以User:len:str
,len
是用户发送消息目标用户的昵称长度。str
是目标昵称和发送内容的拼接
拼接处理在客户端进行。
详情,请参照源代码学习。
客户端:
https://download.csdn.net/download/qq_39603089/10881918
服务端:
https://download.csdn.net/download/qq_39603089/10881905