当前位置:网站首页>多线程高并发服务器:3个问题
多线程高并发服务器:3个问题
2022-06-29 10:09:00 【执迷C++ 的菜鸡】
1.子线程能否关闭监听文件描述符?
2.主线程能否关闭通信文件描述符?
3.多个子线程共享cfd, 会有什么问题发生?
解答1:不能,父子线程共享文件描述符,若子进程关闭监听文件描述符之后,第二个子线程Accept时就会出错。Accept的第一个参数就是监听文件描述符。
解答2:不能,如果主线程关闭了通信文件描述符,直接会导致服务端读取失败,因为Read的第一个参数就是通信文件描述符。
解答3:如果多个客户端同时连接服务端 ,通信文件描述符会出现被覆盖的情况,只有最后一个文件描述符正常,导致只有一个客户端能正常通信。
解决办法:是这些子线程不在共享同一块内存,而改为共享一个数组(将内存分为合适大小的数组),这样就不会导致文件描述符被覆盖。
具体代码如下:
//多线程版本的服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ctype.h>
#include <pthread.h>
#include "wrap.h"
typedef struct info
{
int cfd; //若为-1表示可用, 大于0表示已被占用
int idx;
pthread_t thread;
struct sockaddr_in client;
}INFO;
INFO thInfo[1024];
//线程执行函数
void *thread_work(void *arg)
{
INFO *p = (INFO *)arg;
printf("idx==[%d]\n", p->idx);
char sIP[16];
memset(sIP, 0x00, sizeof(sIP));
printf("new client:[%s][%d]\n", inet_ntop(AF_INET, &(p->client.sin_addr.s_addr), sIP, sizeof(sIP)), ntohs(p->client.sin_port));
int n;
int cfd = p->cfd;
struct sockaddr_in client;
memcpy(&client, &(p->client), sizeof(client));
char buf[1024];
while(1)
{
memset(buf, 0x00, sizeof(buf));
//读数据
n = Read(cfd, buf, sizeof(buf));
if(n<=0)
{
printf("read error or client closed, n==[%d]\n", n);
Close(cfd);
p->cfd =-1; //设置为-1表示该位置可用
pthread_exit(NULL);
}
for(int i=0; i<n; i++)
{
buf[i] = toupper(buf[i]);
}
//发送数据
Write(cfd, buf, n);
}
}
void init_thInfo()
{
int i = 0;
for(i=0; i<1024; i++)
{
thInfo[i].cfd = -1;;
}
}
int findIndex()
{
int i;
for(i=0; i<1024; i++)
{
if(thInfo[i].cfd==-1)
{
break;
}
}
if(i==1024)
{
return -1;
}
return i;
}
int main()
{
//创建socket
int lfd = Socket(AF_INET, SOCK_STREAM, 0);
//设置端口复用
int opt = 1;
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
//绑定--将lfd 和 IP PORT绑定
struct sockaddr_in serv;
bzero(&serv, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = htons(8888);
serv.sin_addr.s_addr = htonl(INADDR_ANY);
Bind(lfd, (struct sockaddr *)&serv, sizeof(serv));
//监听
Listen(lfd, 128);
//初始化
init_thInfo();
int cfd;
int ret;
int idx;
socklen_t len;
pthread_t thread;
struct sockaddr_in client;
while(1)
{
len = sizeof(client);
bzero(&client, sizeof(client));
//获得一个新的连接
cfd = Accept(lfd, (struct sockaddr *)&client, &len);
//创建一个子进程, 让子进程处理连接---接收数据和发送数据
//找数组中空闲的位置
idx = findIndex();
if(idx==-1)
{
Close(cfd);
continue;
}
//对空闲位置的元素的成员赋值
thInfo[idx].cfd = cfd;
thInfo[idx].idx = idx;
memcpy(&thInfo[idx].client, &client, sizeof(client));
//创建子线程---该子线程完成对数据的收发
ret = pthread_create(&thInfo[idx].thread, NULL, thread_work, &thInfo[idx]);
if(ret!=0)
{
printf("create thread error:[%s]\n", strerror(ret));
exit(-1);
}
//设置子线程为分离属性
pthread_detach(thInfo[idx].thread);
}
Close(lfd);
return 0;
}接下来同时同三个客户端测试:

边栏推荐
- Cs231n-2022 module1: overview of key points of neural network (2)
- 共2600页!又一份神级的面试手册面世~
- STM32F1与STM32CubeIDE编程实例-超声波测距传感器驱动
- Detailed explanation of handwritten numeral recognition based on support vector machine (Matlab GUI code, providing handwriting pad)
- When the "Ai x scientific computing" is in progress, Huawei's mindspore competition question is hot, waiting for you!
- 真正的测试 =“半个产品+半个开发”?
- 如何通过WinDbg获取方法参数值
- Does your project need automated testing?
- Free books! The best-selling book "Introduction and practice of OpenCV image processing" has been completed
- 【NLP】文本生成专题1:基础知识
猜你喜欢
随机推荐
Luoqingqi: has high-end household appliances become a red sea? Casati took the lead in breaking the game
By asp Net core downloading files according to the path
VI退出 退出VIM 适用新手
Creating postgre enterprise database by ArcGIS
如何通过WinDbg获取方法参数值
NUC980开源项目16-从SPI FLASH(W25Q128)启动
Cs231n-2022 module1: overview of key points of neural network (2)
反CSRF爆破的三种姿势
np. astype()
Map merges the same keys and values into a list
非凸联合创始人李佐凡:将量化作为自己的终身事业
【无标题】我在密谋一件大事
你的项目需要自动化测试吗?
ModbusTCP协议WIFI无线学习型单路红外模块(圆壳版)
小米手机-解BL锁+开ROOT权限
dropout层
ZABBIX monitors various MySQL indicators
添加通知公告,给在线用户发送通知
Real test = "half product + Half development"?
《Datawhale推荐系统教程》来了!









