练习:TCP多进程通信
2020-03-08 14:31
1426 查看
1.客户端:
socket()-connect()-read()/write()/send()/recv()-close()
2.服务器:
socket()-bind()-listen()-accept()-read()/write()/send()/recv()-close()
3.socket的填充内容,注意其中一个地址信息结构体:struct sockaddr
我们一般不对这个结构体操作。而是对其他结构体赋值,最后再强制转换为(struct sockadd)类型就可以了。
4.注意对长等待函数(阻塞模式)需要考虑中断信号的影响
5.close(fd)函数对fd的关联计数器-1,只有当计数器=0时才关闭fd。因此子进程继承了父进程打开的fd,但是却用不上时需要关闭继承过来的fd。
6.accept()函数传入的是监听套接字,返回是一个全新的连接套接字。2者的fd不同,也即这2个套接字是不同的!
下面代码以TCP通信为例:
/* 头文件 MYHEAD.h */ #ifndef _MYHEAD_H_ #define _MYHEAD_H_ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <unistd.h> #include <signal.h> #include <string.h> #include <wait.h> #include <errno.h> #include <arpa/inet.h> #endif
#include "MYHEAD.h" //使用示例:./client 192.168.1.100 5001 int main(char argc,char **argv){ /* 判断输入参数个数 */ if(argc<3){ printf("Usage:%s <ip> <port>\n",argv[0]); exit(-1); } int fd ; /* 创建socket */ if((fd=socket(AF_INET,SOCK_STREAM,0))<0){ perror("socket"); exit(-1); } uint32_t ip; //容器 /* 192.xxx.xxx.xxx字符串形式,转换,32位,网络字节序 */ if(inet_pton(AF_INET,argv[1],(void *)&ip) != 1){ perror("inet_pton"); exit(-1); } struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = ip; addr.sin_port = htons(atoi(argv[2])); //网络字节序 /* 链接connect */ if(connect(fd,(struct sockaddr *)&addr,sizeof(addr))<0){ perror("connect"); exit(-1); } char buf[30]; int n; while(1){ if(fgets(buf,30,stdin)<0){ //返回0代表没有,返回-1代表出错 perror("fgets"); exit(-1); } if((n=write(fd,buf,strlen(buf))<0)){ //返回实际写入字节数或EOF perror("write"); exit(-1); } if(strcmp(buf,"quit\n") == 0){ //细节:字符串末尾\n close(fd); exit(0); } } }
#include "MYHEAD.h" #define LOCAL_PORT 5001 #define BACKLOG 5 void child_process(int fd,struct sockaddr_in client); //子进程 void handler(int signal); //响应函数 int main(char argc,char **arcv) { int fd,newfd; pid_t pid; /* 绑定:信号--响应函数。子进程退出时,内核会发送SIGCHLD通知父进程 */ signal(SIGCHLD,handler); /* 创建socket */ if((fd=socket(AF_INET,SOCK_STREAM,0))<0){ perror("socket"); exit(-1); } /* 允许绑定地址快速重用 */ int b_reuse = 1; setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int)); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(LOCAL_PORT); //字节序转换 addr.sin_addr.s_addr = htonl(INADDR_ANY); //(INADDR_ANY)表示本机任意网卡地址 /* 绑定服务器的ip,port给刚创建的socket */ if(bind(fd,(struct sockaddr *)&addr,sizeof(addr)) < 0) { perror("bind"); exit(-1); } /* 监听,socket变成被动的 */ if(listen(fd,BACKLOG) < 0) //BACKLOG=同时请求的客户端个数 { perror("listen"); exit(-1); } socklen_t client_len; //容器 struct sockaddr_in client; //容器,存放客户端的地址信息 while(1){ /* 阻塞等待建立链接accept,fd属于监听类socket(被动),newfd属于连接类socket(主动) */ if((newfd = accept(fd,(struct sockaddr *)&client,&client_len))<0) { if(errno != EINTR){ //accept属于阻塞函数,要考虑被中断信号打断的情况。 perror("accept"); exit(-1); } } printf("newfd:%d,fd:%d\n",newfd,fd); //每个进程都有一个独立的表,因此每个进程打印出来的fd数值可以相同 if((pid=fork())<0){ perror("fork"); exit(-1); } if(0 == pid){ //子进程 close(fd); //关闭监听socket,对子进程来说不需要监听 child_process(newfd,client); }else{ //父进程,只负责accept close(newfd); //关闭连接socket,对父进程来说不要连接 } } close(fd); //父进程关闭监听socket return 0; } /* 子进程函数 */ void child_process(int fd,struct sockaddr_in client){ char buf[30]; int n; while(1){ memset(buf,0,30); //清0 if((n=read(fd,buf,30))<0){ //阻塞等待 if(n!=EINTR) //阻塞可能会被中断信号打断,并返回-1 { //任何长等待机制都要考虑被中断的处理方式,用来区分异常错误 perror("read"); exit(-1); } } if(0 == strcmp(buf,"quit\n")){ //细节:字符串末尾的\n printf("client %d ,quit\n",fd); close(fd); exit(0); } if(n>0){ printf("client_ip:%d\n",ntohl(client.sin_addr.s_addr)); printf("client_port:%d\n",ntohs(client.sin_port)); printf(">>%s",buf); } } } /* 信号响应函数 */ void handler(int signal){ if(SIGCHLD == signal){ waitpid(-1,NULL,WNOHANG); //WNOHANG代表非阻塞。 } }
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- Java练习>网络编程>>TCP通信的客户端、服务器端如何实现数据传送
- Linux高级编程复习 第十章 TCP编程模型_TCP通信特点_TCP多进程服务器
- linux下使用多进程实现一个TCP server,使多个客户端和服务器进行通信
- 【原创】TCP Socket 简单练习 --- 新进程辅助通信 分类: Linux --- 应用程序设计 2014-12-23 10:27 64人阅读 评论(0) 收藏
- tcp通信:多进程共享listen socket方式
- 【原创】TCP Socket 简单练习 --- 新进程辅助通信
- Linux网络编程 - TCP Socket 简单练习:新进程辅助通信
- unix环境IPC通信之socket(三),tcp采用并发服务器编程实例,多进程方式 4000
- TCP通信和UDP通信练习
- TCP通信,多进程
- Lniux网络通信二(TCP三次握手,四次挥手 并发服务器)
- 【c#源码】基于TCP通信的客户端断线重连
- 使用Boost asio实现异步的TCP/IP通信
- TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞
- C#网络编程TCP通信的粘包问题讨论
- TCP/ip通信模式
- [问题] 阿里云无法telnet端口 连接失败 无法进行TCP通信
- 基于TCP网络通信的自动升级程序源码分析-客户端接收文件
- 【c#源码】基于TCP通信的客户端断线重连
- 如何基于C语言socket编程实现TCP通信