服务器客户端回射程序-自己设计包的结构
这次是个点对点,不过我自己设计包,包中包括发送的字符串的长度,和实际的字符串,使用结构体来表示。
客户端跟服务器在接收报文时,首先接收字符串的长度这一数值,然后将这一数值作为参数传入readn接收固定长度的字节数字符串。
看代码,首先是服务器端:
1 /*使用发送固定字节数报文的点对点聊天程序*/ 2 #include<stdio.h> 3 #include<unistd.h> 4 #include<sys/types.h> 5 #include<sys/socket.h> 6 #include<errno.h> 7 #include<netinet/in.h> 8 #include<string.h> 9 #include<stdlib.h> 10 struct packet{ 11 int len; 12 char buf[1024]; 13 }; 14 //读取固定字节数目count 15 ssize_t readn(int fd,void* buf,size_t count) 16 { 17 size_t nleft=count; 18 ssize_t nread; 19 char *bufp=(char*)buf; 20 while(nleft>0) 21 { 22 if((nread=read(fd,bufp,nleft))<0) 23 { 24 if(errno==EINTR) 25 continue; 26 return -1; 27 } 28 if(nread==0) 29 return count-nleft; 30 bufp+=nread; 31 nleft-=nread; 32 } 33 return count; 34 } 35 36 ssize_t writen(int fd,void *buf,size_t count) 37 { 38 size_t nleft=count; 39 size_t nwrite; 40 char*bufp=(char*)buf; 41 while(nleft>0) 42 { 43 if((nwrite=write(fd,bufp,nleft))<0) 44 { 45 //注意这里不要将bufp写成了buf 46 if(errno==EINTR) 47 { 48 continue; 49 } 50 return -1; 51 52 } 53 else if(nwrite==0) 54 continue; 55 bufp+=nwrite; 56 nleft-=nwrite; 57 } 58 return count; 59 } 60 61 62 //服务器处理连接的子进程调用的服务函数,conn_fd是已连接描述符 63 void doservice(int conn_fd) 64 { 65 struct packet recvbuf; 66 int packet_len; 67 while(1) 68 { 69 memset(&recvbuf,0,sizeof(recvbuf)); 70 int ret=readn(conn_fd,&recvbuf.len,sizeof(recvbuf.len));//首先读取自己设计的报文中真正的字符串的实际长度 71 if(ret==-1) 72 { 73 perror("readn"); 74 exit(EXIT_FAILURE); 75 } 76 else if(ret==0) 77 { 78 printf("client has closed!!!\n");// 79 break; 80 } 81 packet_len=ntohl(recvbuf.len);//注意网络上传送的数字都应该以网络字节序发送,同理,收到之后,首先应该将其转换为主机字节序 82 ret=readn(conn_fd,&recvbuf.buf,packet_len);//接下来读取真正的报文,其中将上一次收到包中的字符串长度作为第3个参数传入,表示确定读取这么多字节数 83 if(ret==-1) 84 { 85 perror("readn"); 86 exit(EXIT_FAILURE); 87 } 88 else if(0==ret) 89 { 90 printf("client has closed"); 91 break; 92 } 93 fputs(recvbuf.buf,stdout); 94 writen(conn_fd,&recvbuf,4+packet_len);//其中4是表示包中字符串长度的整数所需的4个字节 95 } 96 97 } 98 99 int main() 100 { 101 int sockfd=socket(AF_INET,SOCK_STREAM,0); 102 if(sockfd<0) perror("socket!!!!"); 103 104 int on=1; 105 int result=setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));//启用套接字选项,必须在bind之前完成 106 if(result<0) perror("setsockopt"); 107 108 struct sockaddr_in server_addr; 109 memset(&server_addr,0,sizeof(server_addr)); 110 server_addr.sin_family=AF_INET; 111 server_addr.sin_port=htons(888); 112 server_addr.sin_addr.s_addr=htonl(INADDR_ANY); 113 114 115 int res=bind(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)); 116 if(res<0)perror("bind!!!"); 117 118 res=listen(sockfd,50); 119 if(res<0)perror("listen!!"); 120 121 int conn_fd; 122 struct sockaddr_in peeraddr; 123 int addr_len=sizeof(peeraddr); 124 pid_t pid; 125 while(1) 126 { 127 conn_fd=accept(sockfd,(struct sockaddr*)&peeraddr,&addr_len); 128 printf(" the ip of client:%s,the port of client:%d\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));//打印对等方的ip与端口 129 if(conn_fd<0)perror("accept!!"); 130 pid=fork(); 131 if(pid<0) 132 perror("fork failed"); 133 if(pid==0) 134 { //子进程 135 close(sockfd); //子进程首先关闭监听套接字,因为子进程只利用accept返回的已连接套接字描述符处理连接 136 doservice(conn_fd); 137 exit(EXIT_SUCCESS); //子进程处理完一个连接,直接就结束,否则又回到前面去accept,这是父进程的工作 138 } 139 else close(conn_fd); //父进程首先关闭已连接套接字,然后回到前面,继续监听 140 } 141 142 return 0; 143 }
然后是客户端代码:
1 /*使用发送固定字节数报文的点对点聊天程序*/ 2 3 4 #include<stdio.h> 5 #include<unistd.h> 6 #include<sys/types.h> 7 #include<sys/socket.h> 8 #include<errno.h> 9 #include<netinet/in.h> 10 #include<string.h> 11 #include<stdlib.h> 12 struct packet{ 13 int len; 14 char buf[1024]; 15 }; 16 17 18 ssize_t readn(int fd,void* buf,size_t count) 19 { 20 size_t nleft=count; 21 ssize_t nread; 22 char *bufp=(char*)buf; 23 while(nleft>0) 24 { 25 if((nread=read(fd,bufp,nleft))<0) 26 { 27 if(errno==EINTR) 28 continue; 29 return -1; 30 } 31 else if(nread==0) 32 return count-nleft; 33 bufp+=nread; 34 nleft-=nread; 35 } 36 return count; 37 38 } 39 ssize_t writen(int fd,void *buf,size_t count){ 40 size_t nleft=count; 41 size_t nwrite=0; 42 char*bufp=(char*)buf; 43 while(nleft>0) 44 { 45 if((nwrite=write(fd,bufp,nleft))<0) 46 { 47 //注意这里不要将bufp写成了buf 48 if(errno==EINTR){ 49 continue; 50 } 51 return -1; 52 53 } 54 else if(nwrite==0) 55 continue; 56 bufp+=nwrite; 57 nleft-=nwrite; 58 59 } 60 return count; 61 } 62 63 int main(){ 64 int sockfd= socket(AF_INET,SOCK_STREAM,0); 65 if(sockfd<0)perror("socket"); 66 67 struct sockaddr_in server_addr; 68 memset(&server_addr,0,sizeof(server_addr)); 69 server_addr.sin_family=AF_INET; 70 server_addr.sin_port=htons(888); //this port number is owned by server,and client's port number is appointed by random 71 server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");//服务器端的ip地址 72 73 int res=connect(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)); 74 if(res<0)perror("connect!!!!!!!"); 75 76 struct packet recvbuf; 77 struct packet sendbuf; 78 memset(&recvbuf,0,sizeof(recvbuf)); 79 memset(&sendbuf,0,sizeof(sendbuf)); 80 while(fgets(sendbuf.buf,sizeof(sendbuf.buf),stdin)!=NULL) 81 { 82 int packet_len=strlen(sendbuf.buf); 83 sendbuf.len=htonl(packet_len); 84 writen(sockfd,&sendbuf,4+packet_len);// 85 //readn(sockfd,&recvbuf.len,sizeof(recvbuf.len)); 86 int ret=readn(sockfd,&recvbuf.len,sizeof(recvbuf.len));// 87 if(ret==-1) 88 { 89 perror("readn"); 90 exit(EXIT_FAILURE); 91 } 92 else if(ret<4) 93 { 94 printf("client has closed!!!\n");// 95 break; 96 } 97 packet_len=ntohl(recvbuf.len); 98 ret=readn(sockfd,&recvbuf.buf,packet_len); 99 if(ret==-1) 100 { 101 perror("readn"); 102 exit(EXIT_FAILURE); 103 } 104 else if(ret<packet_len) 105 { 106 printf("client has closed"); 107 break; 108 } 109 fputs(recvbuf.buf,stdout); 110 //writen(conn_fd,&recvbuf,4+packet_len); 111 112 113 //fputs(recvbuf,stdout); 114 } 115 close(sockfd); 116 117 return 0; 118 }
转载于:https://www.cnblogs.com/chess/p/4684741.html
服务器客户端回射程序-自己设计包的结构相关推荐
- 回射程序改进3——消息的群发
前文列表: 简单的回射程序 回射程序改进1 回射程序改进2--群发消息(fork)错误的尝试 目的: 设计一个C/S程序,客户端发送/接收消息,服务端将从客户端接收到的消息群发给其它已连接套接字,产生 ...
- C#下如何实现服务器+客户端的聊天程序
C#下如何实现服务器+客户端的聊天程序 最近也在接触SOCKET编程,在当今这样一个网络时代,很多技术都以网络为中心在诞生,至少我认为是这样的,而SOCKET套接字接口,在实现网络通讯上处于关键地位, ...
- UNIX网络编程笔记(7):回射程序的UDP版本
1.UDP简介 UDP是一个简单的传输层协议,应用进程往一个UDP套接字写入数据,随后被封装到一个UDP数据报,进而又被封装到一个IP数据报,然后发送到目的地.UDP不保证UDP数据报会最终到达目的地 ...
- UNIX网络编程笔记(4):简单的回射程序
上一讲中我们通过调用fork函数实现了一个简单的并发时间获取服务器.这是一个简单的并发服务器框架,然而这里使用这个框架实现一个简单的回射服务器会出现一个问题,这个问题就是僵尸子进程. 1.回射程序 下 ...
- C#下如何实现服务器 + 客户端的聊天程序
最近也在接触SOCKET编程,在当今这样一个网络时代,很多技术都以网络为中心在诞生,至少我认为是这样的,而SOCKET套接字接口,在实现网络通讯上处于关键地位,所以不会SOCKET是不行的. 首先,本 ...
- 基于TCP的一对回射客户/服务器程序及其运行过程分析( 下 )
执行分析 1. 打开服务器进程: 2. 执行netstat -a命令观察当前的连接状态: 第1条连接记录说明:绑定了本地主机的任意IP,端口为9877,目前处于监听状态. 3. 打开客户进程: 4. ...
- 第十篇:基于TCP的一对回射客户/服务器程序及其运行过程分析( 上 )
前言 本文将讲解一对经典的客户/服务器回射程序,感受网络编程的大致框架( 该程序稍作改装即可演变成各种提供其他服务的程序 ):同时,还将对其运行过程加以分析,观察程序背后协议的执行细节,学习调试网络程 ...
- UNIX网络编程卷1 回射客户程序 TCP客户程序设计范式
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 下面我会介绍同一个使用 TCP 协议的客户端程序的几个不同版本,分别是停等版本.select ...
- linux tcp客户端端口号,Linux网络编程--服务器客户端(TCP实现)
Linux下的一个服务器客户端的小程序,基于TCP的实现:服务器可以同时接受多个客户的接入,通过子进程处理客户请求,下面的例子中,服务器只将客户的IP和端口以及发送的信息显示,然后原样的将客户发送的信 ...
最新文章
- TMG2010 之创建访问规则
- JS (intermediate value).Format is not a function问题解决
- css模糊_如何使用CSS模糊图像?
- php yii多表查询
- cv2 imwrite中文路径_python3下使用cv2.imwrite存储带有中文路径图片的方法
- VNC实现Windows远程访问Ubuntu 16.04【转载】
- 程序员的自我救赎---4.2:消息中心讲解与应用
- 2013年蓝桥杯题集C本科B
- java 各组件单击总数_java 获取面板上有多少个组件
- 基于WF的意见征集6(浅析)
- 左手用R右手Python系列16——XPath与网页解析库
- Atitit.struts2体系结构大总结
- 小马Win7永久激活工具—OemY3.1 NT6通用完美激活
- Filezilla server连接Ubuntu被服务器拒绝及中文乱码问题解决
- 《生物化学与分子生物学》----绪论----听课笔记(一)
- 概率论与数理统计的基本概念
- Android从一个应用程序启动第三方应用app
- Windows 安装MySQL 8.0 超详细教程(mysql 8.0.30)
- [转]React 入门实例教程
- SAM4E单片机之旅——10、UART与MCK之PLL
热门文章
- 成功解决slave无datanode问题
- python图例重复显示_matplotlib中的legend()——用于显示图例
- 算法之组合数学及其算法篇(一) ----- 排列与组合
- 达梦想oracle迁移,oracle存储过程迁移达梦心得
- elasticsearch入门hello world (macos)【一】下载运行
- Leetcode-121. 买卖股票的最佳时机
- spring扫描自定义注解并进行操作
- 笔记-信息化与系统集成技术-人工智能的特点
- el-table中每列设置同样的宽度导致表格宽度没法实现100%布局
- Android中TimePicker时间选择器的使用和获取选择的时和分