套接字编程 (多进程多线程)
三次握手:
主动发起连接请求端,发送SYN标志位,请求建立连接。携带序号、数据字节数(0)、滑动窗口大小。
被动接受连接请求端,回复ACK标志位,同时携带 SYN 请求标志位。 携带序号、确认序号、数据字节函数(0)、滑动窗口大小
主动大气连接请求端,发送 ACK 标志位,应答服务器连接请求。携带确认序号。
四次挥手:
主动关闭连接请求端,发送 FIN标志位
被动关闭连接请求端,应答 ACK 标志位。---- 半关闭完成
被动关闭连接请求端,返送 FIN 标志位
主动关闭连接请求端,应答 ACK 标志位---- 连接全部关闭
文章图片
文章图片
滑动窗口:
发送给连接对端,本端缓冲区大小(实时),保证数据不会丢失
错误处理函数:
封装目的:
在server.c 编程过程中突出逻辑,将出错处理与逻辑分开,可以直接跳转man 手册
【wrap.c】【wrap.h】
存放网络通信相关 常用自定义函数函数声明
命名方式:系统调用首字母大写,方便查看man手册
如:Listen()
联合编译:
server.c 和wrap.c生成server
client.c 和 wrap.c 生成client
多进程并发服务器:
1.socket();创建 监听套接字1fd
2.bind()绑定地址结构struct sockaddr_inaddr;
3.listen();
4.while(1){
cfd = accept();接受客户端连接请求
pid=fork();
if(pid==0){
close(1fd)
read()
小 --》 大
write()
} else if (pid》0){
close(cfd);关闭与客户端通信的套接字 cfd
continue
}
}
5.子进程:
close(1fd)
read()
小 --》大
write()
父进程:
close(cfd);
注册信号捕捉函数;SIGCHLD
在回调函数中, 完成子进程的回收
while(waitpid());
//server#include
#include
#include
#include
#include
#include
#include
#include
#include#define SRV_PORT 9999
void catch_child(int signum){
(void)signum;
while(waitpid(0,NULL,WNOHANG)>0);
return ;
}int main(){int lfd,cfd;
pid_t pid;
int ret,i;
char buf[BUFSIZ];
char str[BUFSIZ];
struct sockaddr_in srv_addr,clt_addr;
socklen_t clt_addr_len;
bzero(&srv_addr,sizeof(srv_addr));
//将地址结构清零
srv_addr.sin_family = AF_INET;
srv_addr.sin_port= htons(SRV_PORT);
srv_addr.sin_addr.s_addr= htonl(INADDR_ANY);
lfd = socket(AF_INET,SOCK_STREAM,0);
bind(lfd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
listen(lfd,128);
clt_addr_len =sizeof(clt_addr);
while(1){
cfd = accept(lfd,(struct sockaddr*)&clt_addr,&clt_addr_len);
printf("receive from %s at PORT %d\n",
inet_ntop(AF_INET,&clt_addr.sin_addr,str,sizeof(str)),
ntohs(clt_addr.sin_port));
pid = fork();
if(pid<0){
perror("fork error");
exit(1);
}else if(pid==0){
close(lfd);
break;
}else{
struct sigaction act;
act.sa_handler = catch_child;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
ret=sigaction(SIGCHLD,&act,NULL);
if(ret!=0){
perror("sigaction error");
exit(1);
}close(cfd);
continue;
}}
if(pid==0){
for(;
;
){
ret = read(cfd,buf,sizeof(buf));
if(ret==0){
close(cfd);
exit(1);
}
for(i=0;
i
#include
#include
#include#define SERV_PORT9999void sys_err(const char* str){
perror(str);
exit(1);
}
int main(){
int cfd;
char buf[BUFSIZ];
struct sockaddr_in serv_addr;
//服务器地址结构serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET,"127.0.0.1",&serv_addr.sin_addr.s_addr);
cfd = socket(AF_INET,SOCK_STREAM,0);
if(cfd==-1){
sys_err("socket error");
}
int ret=connect(cfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
if(ret!=0){
sys_err("connect error");
}
while(1){
ret =read(STDIN_FILENO,buf,sizeof(buf));
write(cfd,buf,ret);
ret=read(cfd,buf,sizeof(buf));
write(STDOUT_FILENO,buf,ret);
sleep(1);
}
close(cfd);
return 0;
}
多线程并发服务器: server.c
1.socket()创建 监听套接字 1fd
2.bind()绑定地址结构 struct sockaddr_in addr;
3.listen()
4.while(1){
cfd = accept(1fd);
pthread_create(&tid,NULL,tfn,NULL);
pthread——detach(tid)
}
5.子线程
void* tfn(void* arg){
close(1fd)
read(cfd)
小-->大
write(cfd)
pthread_exit((void*)10);
}
#include
#include
#include
#include
#include
#include
#include
#include#define MAXLINE 8192#define SERV_PORT 8000struct s_info{//定义一个结构体,将地址结构和 cfd 捆绑
struct sockaddr_in cliaddr;
int connfd;
};
void* do_work(void* arg){
int n,i;
struct s_info* ts= (struct s_info*)arg;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
while(1){
n =read(ts->connfd,buf,MAXLINE);
if(n==0){
printf("the client %d close\n",ts->connfd);
break;
}
printf("receive from %s at PORT %d\n",
inet_ntop(AF_INET,&(*ts).cliaddr.sin_addr,str,sizeof(str)),
ntohs((*ts).cliaddr.sin_port));
write(STDOUT_FILENO,buf,n);
for(i=0;
iconnfd,buf,n);
}
close(ts->connfd);
return (void*)0;
}int main(){struct sockaddr_in servaddr,cliaddr;
socklen_t cliaddr_len;
int listenfd,connfd;
pthread_t tid;
struct s_info ts[256];
int i =0;
listenfd =socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port= htons(SERV_PORT);
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
listen(listenfd,128);
printf("accepting client connect\n");
while(1){
cliaddr_len =sizeof(cliaddr);
connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddr_len);
ts[i].cliaddr=cliaddr;
ts[i].connfd= connfd;
pthread_create(&tid,NULL,do_work,(void*)&ts[i]);
pthread_detach(tid);
i++;
}
return 0;
}
【套接字编程 (多进程多线程)】
推荐阅读
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 爱就是希望你好好活着
- 昨夜小楼听风
- 知识
- 死结。
- 我从来不做坏事
- 烦恼和幸福
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- Linux下面如何查看tomcat已经使用多少线程
- 说得清,说不清