这次是个点对点,不过我自己设计包,包中包括发送的字符串的长度,和实际的字符串,使用结构体来表示。

  客户端跟服务器在接收报文时,首先接收字符串的长度这一数值,然后将这一数值作为参数传入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

服务器客户端回射程序-自己设计包的结构相关推荐

  1. 回射程序改进3——消息的群发

    前文列表: 简单的回射程序 回射程序改进1 回射程序改进2--群发消息(fork)错误的尝试 目的: 设计一个C/S程序,客户端发送/接收消息,服务端将从客户端接收到的消息群发给其它已连接套接字,产生 ...

  2. C#下如何实现服务器+客户端的聊天程序

    C#下如何实现服务器+客户端的聊天程序 最近也在接触SOCKET编程,在当今这样一个网络时代,很多技术都以网络为中心在诞生,至少我认为是这样的,而SOCKET套接字接口,在实现网络通讯上处于关键地位, ...

  3. UNIX网络编程笔记(7):回射程序的UDP版本

    1.UDP简介 UDP是一个简单的传输层协议,应用进程往一个UDP套接字写入数据,随后被封装到一个UDP数据报,进而又被封装到一个IP数据报,然后发送到目的地.UDP不保证UDP数据报会最终到达目的地 ...

  4. UNIX网络编程笔记(4):简单的回射程序

    上一讲中我们通过调用fork函数实现了一个简单的并发时间获取服务器.这是一个简单的并发服务器框架,然而这里使用这个框架实现一个简单的回射服务器会出现一个问题,这个问题就是僵尸子进程. 1.回射程序 下 ...

  5. C#下如何实现服务器 + 客户端的聊天程序

    最近也在接触SOCKET编程,在当今这样一个网络时代,很多技术都以网络为中心在诞生,至少我认为是这样的,而SOCKET套接字接口,在实现网络通讯上处于关键地位,所以不会SOCKET是不行的. 首先,本 ...

  6. 基于TCP的一对回射客户/服务器程序及其运行过程分析( 下 )

    执行分析 1. 打开服务器进程: 2. 执行netstat -a命令观察当前的连接状态: 第1条连接记录说明:绑定了本地主机的任意IP,端口为9877,目前处于监听状态. 3. 打开客户进程: 4. ...

  7. 第十篇:基于TCP的一对回射客户/服务器程序及其运行过程分析( 上 )

    前言 本文将讲解一对经典的客户/服务器回射程序,感受网络编程的大致框架( 该程序稍作改装即可演变成各种提供其他服务的程序 ):同时,还将对其运行过程加以分析,观察程序背后协议的执行细节,学习调试网络程 ...

  8. UNIX网络编程卷1 回射客户程序 TCP客户程序设计范式

    本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 下面我会介绍同一个使用 TCP 协议的客户端程序的几个不同版本,分别是停等版本.select ...

  9. linux tcp客户端端口号,Linux网络编程--服务器客户端(TCP实现)

    Linux下的一个服务器客户端的小程序,基于TCP的实现:服务器可以同时接受多个客户的接入,通过子进程处理客户请求,下面的例子中,服务器只将客户的IP和端口以及发送的信息显示,然后原样的将客户发送的信 ...

最新文章

  1. TMG2010 之创建访问规则
  2. JS (intermediate value).Format is not a function问题解决
  3. css模糊_如何使用CSS模糊图像?
  4. php yii多表查询
  5. cv2 imwrite中文路径_python3下使用cv2.imwrite存储带有中文路径图片的方法
  6. VNC实现Windows远程访问Ubuntu 16.04【转载】
  7. 程序员的自我救赎---4.2:消息中心讲解与应用
  8. 2013年蓝桥杯题集C本科B
  9. java 各组件单击总数_java 获取面板上有多少个组件
  10. 基于WF的意见征集6(浅析)
  11. 左手用R右手Python系列16——XPath与网页解析库
  12. Atitit.struts2体系结构大总结
  13. 小马Win7永久激活工具—OemY3.1 NT6通用完美激活
  14. Filezilla server连接Ubuntu被服务器拒绝及中文乱码问题解决
  15. 《生物化学与分子生物学》----绪论----听课笔记(一)
  16. 概率论与数理统计的基本概念
  17. Android从一个应用程序启动第三方应用app
  18. Windows 安装MySQL 8.0 超详细教程(mysql 8.0.30)
  19. [转]React 入门实例教程
  20. SAM4E单片机之旅——10、UART与MCK之PLL

热门文章

  1. 成功解决slave无datanode问题
  2. python图例重复显示_matplotlib中的legend()——用于显示图例
  3. 算法之组合数学及其算法篇(一) ----- 排列与组合
  4. 达梦想oracle迁移,oracle存储过程迁移达梦心得
  5. elasticsearch入门hello world (macos)【一】下载运行
  6. Leetcode-121. 买卖股票的最佳时机
  7. spring扫描自定义注解并进行操作
  8. 笔记-信息化与系统集成技术-人工智能的特点
  9. el-table中每列设置同样的宽度导致表格宽度没法实现100%布局
  10. Android中TimePicker时间选择器的使用和获取选择的时和分