牛客网多线程socket通信案列完善版本
刚开始自己享用for循环直接实现回收,发现还是存在问题,话不多说代码里面有很多注释。希望有改进的同学私信我。
//这是服务器的
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
// 定义最大连接数为3
const int maxLink = 3; //C里只能用#define定义常量,但C++却可以用const。
struct communPara{
struct sockaddr_in clientInfo;
int cfd ;
pthread_t tid;
};
struct communPara ccp[maxLink]; //与客户端通信参数 client communication parameters
void* communication(void * arg){
struct communPara* ccp=(struct communPara*)arg;
//输出客户端信息
char lientIP[16]={0};
inet_ntop(AF_INET,&ccp->clientInfo.sin_addr.s_addr,lientIP,sizeof(lientIP));
unsigned short clientPort=ntohs(ccp->clientInfo.sin_port);
printf("client's IP is:%s, client's port is:%d\n",lientIP,clientPort);
sleep(0.5);
// 1.通信
char recvSendBuf[1024];
while(1){
//清空缓存
memset(recvSendBuf,0,sizeof(recvSendBuf));
int len = read(ccp->cfd,recvSendBuf,sizeof(recvSendBuf));
if(len==-1){
perror("read");
break;//就算有问题也要去释放资源
}else if(len>0){
printf("server receive data: %s\n",recvSendBuf);
}else if(len==0){
printf("%ld客户端断开\n",ccp->tid);
break;
}
write(ccp->cfd,recvSendBuf,sizeof(recvSendBuf));
}
// 2.释放文件描述符
close(ccp->cfd);
// 3.将传入的结构体清零;
bzero(&ccp->clientInfo,sizeof(ccp->clientInfo));
ccp->cfd=-1;
ccp->tid=-1;
return NULL;
}
int main() {
char serverIP[] = {"192.168.73.100"};
unsigned short serverPort = 9090;
// 1.创建socket,获取连接文件描述符
int lfd = socket(AF_INET,SOCK_STREAM,0);
if(lfd == -1){ perror("socket"); exit(-1);}
// 2.封装端口
struct sockaddr_in serverInfo;
serverInfo.sin_family = AF_INET;
serverInfo.sin_addr.s_addr = INADDR_ANY;
serverInfo.sin_port = htons(serverPort);
// 3.bind绑定服务器IP和端口,和文件描述符
int ret = bind(lfd,(struct sockaddr*) &serverInfo,sizeof(serverInfo));
if(ret == -1){ perror("bind"); exit(-1);}
// 4.listen监听端口
ret = listen(lfd,maxLink);
if(ret == -1){ perror("listen"); exit(-1);}
// 初始化数据
int max=sizeof(ccp)/sizeof(ccp[0]);
for(int i=0;i<max;++i){
bzero(&ccp[i],sizeof(ccp[i]));
ccp[i].cfd=-1;
ccp[i].tid=-1;
}
//反复遍历ccp数组找到可用的,(大家可以考虑释放资源的序号存放在堆栈或者队列中,
//我们只要去使用其中标记为-1的资源)
while(1){
struct sockaddr_in clientInfo;
socklen_t len = sizeof(clientInfo);
int cfd=accept(lfd,(struct sockaddr*)&clientInfo,&len);//阻塞函数
// 从这个数组中找到一个可以用的sockInfo元素
struct communPara *pinfo;
for(int i=0;i<max;++i){
if(ccp[i].cfd==-1){
pinfo=&ccp[i];
break;
}
if(i==max-1){
sleep(1);
i=-1;
}
}
pinfo->cfd=cfd;
memcpy(&pinfo->clientInfo,&clientInfo,len);
// 创建子线程
pthread_create(&pinfo->tid, NULL, communication, pinfo);
pthread_detach(pinfo->tid);
}
// for(int i=0;i<max;++i){
// // if(ccp[i].tid!=-1){ //有数据证明不可用
// // if(i==max-1) {
// // i=-1;
// // sleep(2);
// // }
// // continue;
// // }else{
// // // 5.accept接受客户端连接(循环里)
// // socklen_t len = sizeof(ccp[i].clientInfo);
// // ccp[i].cfd=accept(lfd,(struct sockaddr*)&ccp[i].clientInfo,&len);
// // if(ccp[i].cfd==-1){ perror("accept"); continue;}
// // // 6.创建子线程负责通信(参数:clientInfo,cfd,tid)
// // //pthread_create函数不会让主线程不阻塞,所以可以在communication中释放资源
// // pthread_create(&ccp[i].tid,NULL,communication,&ccp[i]);
// // pthread_detach(ccp[i].tid);
// }
// }
close(lfd);
return 0;
}
注:纯属学习交流。如果有问题或者涉及版权请联系我:15909440083.
如果有同学想看看效果可以改一下自己的IP
// TCP通信的客户端
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main() {
char serverIP[]={"192.168.73.100"};
unsigned short serverPort=9090;
// 1.创建套接字
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1) { perror("socket"); exit(-1);}
// 2.连接服务器端
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
inet_pton(AF_INET, serverIP, &serveraddr.sin_addr.s_addr);
serveraddr.sin_port = htons(serverPort);
int ret = connect(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
if(ret == -1) { perror("connect"); exit(-1); }
// 3. 通信
char recvBuf[1024];
int i = 0;
while(1) {
memset(recvBuf,0,sizeof(recvBuf));
sprintf(recvBuf, "data : %d", i++);
sleep(1); //这个只是让程序发送的慢一些//尽量让中断(ctrl+c)发生在睡眠的时候,要不然服务器那边读数据会有问题
// 给服务器端发送数据
write(fd, recvBuf, strlen(recvBuf)+1);
memset(recvBuf,0,sizeof(recvBuf));
int len = read(fd, recvBuf, sizeof(recvBuf));
if(len == -1) {
perror("read");
exit(-1);
// break;
} else if(len > 0) {
printf("recv server : %s\n", recvBuf);
} else if(len == 0) {
// 表示服务器端断开连接
printf("server closed...\n");
break;
}
}
// 关闭连接
close(fd);
return 0;
}
编译的代码也放在这
g++ gyw_server_thread.c -o gywpths -lpthread
gcc gyw_client.c -o gywc
./gywpths
./gywc