zoukankan      html  css  js  c++  java
  • 服务器客户端回射程序-自己设计包的结构

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

      客户端跟服务器在接收报文时,首先接收字符串的长度这一数值,然后将这一数值作为参数传入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!!!
    ");//
     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
    ",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!!!
    ");//
     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 }
    手里拿着一把锤子,看什么都像钉子,编程界的锤子应该就是算法了吧!
  • 相关阅读:
    es3的语法来模拟es5的bind方法
    js判断变量的类型(使用闭包来玩一把)
    获取一组时间中的最近的日期
    可以设置超时版的的fetch
    错误排查
    如何查看Linux的CPU负载
    shell脚本操作mysql数据库,使用mysql的-e参数可以执行各种sql的(创建,删除,增,删,改、查)等各种操作
    Swoole server函数列表(转载)
    php的反射
    PHP共享内存
  • 原文地址:https://www.cnblogs.com/chess/p/4684741.html
Copyright © 2011-2022 走看看