本次笔记主要是对上节代码的优化。
上节代码:Linux学习-通信-Socket封装
如果我们客户端有多次消息进行发送,而有一个进程一直在占用,上面的代码就满足不了我们的需求。比如一直有个while(1) 在占用。
#include<stdio.h>
#include"mySocketAPI.h"
int main(char *argc,char **argv)
{
int s_fd;
int c_fd;
char buf[32] = {};
s_fd = socketServerCreate(argv[1],argv[2]);
while(1){
c_fd = accept(s_fd,NULL,NULL);
read(c_fd,buf,32);
printf("get msg:%s\n",buf);
**while(1);**
}
return 0;
}
这样客户端只能发送一次消息,因为这里while(1) 死循环一直将通道占用。
有以下方法进行优化
1. 使用父子进程优化。
#include<stdio.h>
#include"mySocketAPI.h"
int main(char *argc,char **argv)
{
int s_fd;
int c_fd;
char buf[32] = {};
s_fd = socketServerCreate(argv[1],argv[2]);
while(1){
c_fd = accept(s_fd,NULL,NULL);
memset(buf,'\0',32); // 清空buf内容
if(fork() == 0){ //fork()为0时候执行子进程
read(c_fd,buf,32);
printf("get msg:%s\n",buf);
while(1);
}
}
return 0;
}
父进程一直在等接受客户端的消息,不管子进程进行的如何。就算当前的子进程未执行完,也直接进行下一个子进程。
2. 使用线程进行优化
函数原型:
int pthread_create(pthread_t *restrict tidp,
const pthread_attr_t *restrict attr,
void *(*start_rtn)(void),
void *restrict arg);
- tidp为指向线程标识符的指针。返回成功时,由tidp指向的内存单元被设置为新创建线程的线程ID。
- attr用来设置线程属性。
- start_rtn是线程运行函数的起始地址,新创建的线程从start_rtn函数的地址开始运行。
- arg是运行函数的参数。该函数只有一个万能指针参数arg,如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg的参数传入。
#include<stdio.h>
#include"mySocketAPI.h"
#include<pthread.h>
int c_fd; //c_fd定义为全局变量
void fun()
{
char buf[32] = {};
memset(buf,'\0',32); //清空buf
read(c_fd,buf,32);
printf("get msg:%s\n",buf);
while(1);
}
int main(char *argc,char **argv)
{
int s_fd;
pthread_t t1; //创建名为t1的线程
s_fd = socketServerCreate(argv[1],argv[2]);
while(1){
c_fd = accept(s_fd,NULL,NULL);
pthread_create(&t1,NULL,(void*)fun,NULL);
//&t1:线程地址
//第二个参数 这里用NULL
//(void*)fun 执行这个函数
//NULL:不需要给函数传参
}
return 0;
}
编译服务端代码,这里见了线程后编译游戏而变化,多了 -lpthread 如图: