zoukankan      html  css  js  c++  java
  • socket编程——一个简单的例子

    从一个简单的使用TCP例子开始socket编程,其基本步骤如下:

    server                                                  client

     

    +++++++                                          ++++++++

    创建socket                                          创建socket

    +++++++                                          ++++++++

          |                                                         |

          |                                                         |

          |                                                         |

    +++++++                                          ++++++++

    地址赋值(                                           地址赋值(

    自己的地址)                                        服务器地址)

    +++++++                                          ++++++++

          |                                                         |

          |                                                         |

          |                                                         |

    ++++++++                                              |

    用bind绑定                                                |

    socket和地址                                             |

    ++++++++                                              |

          |                                                         |

          |                                                         |

          |                                                         |

    +++++++                                                 |

    listen                                                         |

    +++++++                                                  |

          |                                                    ++++++++++

          |   <------------------------------          connect 服务器         

          |                                                    ++++++++++

    +++++++                                                  |

    accept                                                        |

    +++++++                                                  |

          |                                                           |

          |                                                    +++++++++

          |                                                     recv 和send

          |                                                     进行数据处理

          |                                                     +++++++++

    +++++++++                                                |

    用accept得到                                                 |

    的socket进行                                                 |

    recv 和 send                                                 |

    +++++++++                                                |

          |                                                             |

          |                                                             |

          |                                                             |

    +++++++++                                        +++++++++

    close socket                                         close socket

    +++++++++                                        +++++++++

     

    根据以上步骤,服务器端的代码为

    #include <stdio.h>  
    #include <string.h>  
    #include <sys/socket.h>  
    #include <netinet/in.h>  
    #include <stdlib.h>  
    #include <syslog.h>  
    #include <errno.h>  
    #define MAX_LISTEN_NUM 5  
    #define SEND_BUF_SIZE 100  
    #define RECV_BUF_SIZE 100  
    #define LISTEN_PORT 1010  
    int main()  
    {  
      int listen_sock = 0;  
      int app_sock = 0;  
      struct sockaddr_in hostaddr;  
      struct sockaddr_in clientaddr;  
      int socklen = sizeof(clientaddr);  
      char sendbuf[SEND_BUF_SIZE] = {0};  
      char recvbuf[RECV_BUF_SIZE] = {0};  
      int sendlen = 0;  
      int recvlen = 0;  
      int retlen = 0;  
      int leftlen = 0;  
      char *ptr = NULL;  
      memset((void *)&hostaddr, 0, sizeof(hostaddr));  
      memset((void *)&clientaddr, 0, sizeof(clientaddr));  
      hostaddr.sin_family = AF_INET;  
      hostaddr.sin_port = htons(LISTEN_PORT);  
      hostaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
      listen_sock = socket(AF_INET, SOCK_STREAM, 0);  
      if(listen_sock < 0)  
      {  
          syslog(LOG_ERR, "%s:%d, create socket failed", __FILE__, __LINE__);  
          exit(1);  
      }  
      if(bind(listen_sock, (struct sockaddr *)&hostaddr, sizeof(hostaddr)) < 0)  
      {  
          syslog(LOG_ERR, "%s:%d, bind socket failed", __FILE__, __LINE__);  
          exit(1);  
      }  
      if(listen(listen_sock, MAX_LISTEN_NUM) < 0)  
      {  
          syslog(LOG_ERR, "%s:%d, listen failed", __FILE__, __LINE__);  
          exit(1);  
      }  
      while(1)  
      {  
          app_sock = accept(listen_sock, (struct sockaddr *)&clientaddr, &socklen);  
          if(app_sock < 0)  
         {  
            syslog(LOG_ERR, "%s:%d, accept failed", __FILE__, __LINE__);  
            exit(1);  
         }  
         sprintf(sendbuf, "welcome %s:%d here!/n", inet_ntoa(clientaddr.sin_addr.s_addr), clientaddr.sin_port);  
         //send data  
         sendlen = strlen(sendbuf) +1;  
         retlen = 0;  
         leftlen = sendlen;  
         ptr = sendbuf;  
         //while(leftlen)  
         {  
             retlen = send(app_sock, ptr, sendlen, 0);  
          if(retlen < 0)  
          {  
              if(errno == EINTR)  
                retlen = 0;  
            else  
                exit(1);  
          }  
          leftlen -= retlen;  
          ptr += retlen;  
         }  
         //receive data  
         recvlen = 0;  
         retlen = 0;  
         ptr = recvbuf;  
         leftlen = RECV_BUF_SIZE -1;  
         //do  
         {  
             retlen = recv(app_sock, ptr, leftlen, 0) ;  
          if(retlen < 0)  
          {  
              if(errno == EINTR)  
                retlen = 0;  
            else  
                exit(1);  
          }  
          recvlen += retlen;  
          leftlen -= retlen;  
          ptr += retlen;  
         }  
         //while(recvlen && leftlen);  
         printf("receive data is : %s", recvbuf);  
        close(app_sock);  
      }  
      close(listen_sock);  
        
      return 0;  
        
        
    }  

    客户端代码为:

    #include <stdio.h>  
    #include <string.h>  
    #include <sys/socket.h>  
    #include <netinet/in.h>  
    #include <syslog.h>  
    #include <errno.h>  
    #include <stdlib.h>  
    #define MAX_LISTEN_NUM 5  
    #define SEND_BUF_SIZE 100  
    #define RECV_BUF_SIZE 100  
    #define SERVER_PORT 1010  
    int main()  
    {  
        int sock_fd = 0;  
        char recvbuf[RECV_BUF_SIZE] = {0};  
        char sendbuf[SEND_BUF_SIZE] = {0};  
        int recvlen = 0;  
        int retlen = 0;  
        int sendlen = 0;  
        int leftlen = 0;  
        char *ptr = NULL;  
        struct sockaddr_in ser_addr;  
          
        memset(&ser_addr, 0, sizeof(ser_addr));  
        ser_addr.sin_family = AF_INET;  
        inet_aton("127.0.0.1", (struct in_addr *)&ser_addr.sin_addr);  
        ser_addr.sin_port = htons(SERVER_PORT);  
        sock_fd = socket(AF_INET, SOCK_STREAM, 0);  
        if(sock_fd < 0)  
        {  
            syslog(LOG_ERR, "%s:%d, create socket failed", __FILE__, __LINE__);  
            exit(1);  
        }  
        if(connect(sock_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr)) < 0)  
        {  
            syslog(LOG_ERR, "%s:%d, connect socket failed", __FILE__, __LINE__);  
            exit(1);  
        }  
         //receive data  
         recvlen = 0;  
         retlen = 0;  
         ptr = recvbuf;  
         leftlen = RECV_BUF_SIZE -1;  
         //do  
         {  
             retlen = recv(sock_fd, ptr, leftlen, 0) ;  
          if(retlen < 0)  
          {  
              if(errno == EINTR)  
                retlen = 0;  
            else  
                exit(1);  
          }  
          recvlen += retlen;  
          leftlen -= retlen;  
          ptr += retlen;  
         }  
         //while(recvlen && leftlen);  
         printf("receive data is : %s", recvbuf);  
         sprintf(sendbuf, "hello server/n");  
         //send data  
         sendlen = strlen(sendbuf) +1;  
         retlen = 0;  
         leftlen = sendlen;  
         ptr = sendbuf;  
        // while(leftlen)  
         {  
             retlen = send(sock_fd, ptr, sendlen, 0);  
          if(retlen < 0)  
          {  
              if(errno == EINTR)  
                retlen = 0;  
            else  
                exit(1);  
          }  
          leftlen -= retlen;  
          ptr += retlen;  
         }  
         close(sock_fd);  
          
    }  

    现在一个简单的使用tcp的socket通信的例子已经完成了,这里有几个需要说明的问题

    1)头文件:

    sys/socket.h   包含了socket相关的函数,如socket,send 和recv, 以及struct sockaddr等

    netinet/in.h    包含了地址结构,如struct sockaddr_in

    errno.h           包含了errno 和 EINTR

    syslog.h         包含了syslog相关的信息,其打印结果在/var/log/messages里面

    2)socket地址

    对于IPv4来说,其地址用的是struct sockaddr_in,具体结构如下

    struct in_addr {  
      in_addr_t   s_addr;           /* 32-bit IPv4 address */  
                                    /* network byte ordered */  
    };  
      
    struct sockaddr_in {  
      uint8_t         sin_len;      /* length of structure (16) */  
      sa_family_t     sin_family;   /* AF_INET */  
      in_port_t       sin_port;     /* 16-bit TCP or UDP port number */  
                                    /* network byte ordered */  
      struct in_addr  sin_addr;     /* 32-bit IPv4 address */  
                                    /* network byte ordered */  
      char            sin_zero[8];  /* unused */  
    };  
    其中sin_len我们一般不关注,也不填(只有在使用routing socket的时候才用到,被内核用来处理各种协议簇的地址结构)。
    bind, connect, sendto, 和 sendmsg会把socket地址从程序传递给内核; 而accept, recvfrom, recvmsg, getpeername, 和
    getsockname会把地址从内核传递给程序。因为不同协议簇的地址结构是不一样的,所以必须要有一个通用的指针来传递地址,
    对于ANSI C来说我们一般使用void *,但是socket产生早于ANSI C,所以也就没有使用这个机制,而是使用一个通用的地址结构
    struct sockaddr来处理的
    struct sockaddr {  
      uint8_t      sa_len;  
      sa_family_t  sa_family;    /* address family: AF_xxx value */  
      char         sa_data[14];  /* protocol-specific address */  
    }; 
    IPv6的socket地址为struct sockaddr_in6
    
    
    struct in6_addr {  
      uint8_t  s6_addr[16];          /* 128-bit IPv6 address */  
                                     /* network byte ordered */  
    };  
      
    #define SIN6_LEN      /* required for compile-time tests */  
      
    struct sockaddr_in6 {  
      uint8_t         sin6_len;      /* length of this struct (28) */  
      sa_family_t     sin6_family;   /* AF_INET6 */  
      in_port_t       sin6_port;     /* transport layer port# */  
                                     /* network byte ordered */  
      uint32_t        sin6_flowinfo; /* flow information, undefined */  
      struct in6_addr sin6_addr;     /* IPv6 address */  
                                     /* network byte ordered */  
      uint32_t        sin6_scope_id; /* set of interfaces for a scope */  
    };  
    
    
    对于sockaddr-in6来说,我们不能用通用的地址struct sockaddr来存储了,而是产用新的通用地址结构struct sockaddr_storage,
    这个结构足够大可以存储任何系统支持的地址。
    struct sockaddr_storage {  
      uint8_t      ss_len;       /* length of this struct (implementation dependent) */  
      sa_family_t  ss_family;    /* address family: AF_xxx value */  
      /* implementation-dependent elements to provide: 
       * a) alignment sufficient to fulfill the alignment requirements of 
       *    all socket address types that the system support 
       * b) enough storage to hold any type of socket address that the 
       *    system supports. 
       */  
    };  
    几种常见的地址结构
    3) 相关函数的的length
    
    对于从程序传地址给内核的函数(如connect),其长度是一个整型值,告诉内核要copy的地址长度。
    
    对于从内核传递给程序的函数(如accpt),其长度是一个整型指针,是一个value-result参数。有两个目的:一告诉内核地址结构的长度,
    让内核在copy的时候不要超过这个长度;二返回内核真正copy的长度。 4)字节序 socket相关的函数都是使用网络字节序 5)地址转换函数 inet_aton, inet_ntoa, and inet_addr把IPv4字符串地址转为32位的网络字节序地址 inet_ptonand inet_ntop可以转换IPv4和IPv6的地址 6)listen中的backlog 要知道这个值的含义先用说一下,对于一个listen的socket,有两个队列:一个是incomplete connection队列(仅仅收到SYN);
    一个是complete connection队列(三次握手完成)。accept函数就是在complete connection队列中取一个socket。backlog就是指队列的个数,
    但不行的是各个地方都没有明确定义这个值,没有说明究竟代表了哪个队列,或是两个队列之和。一般来说可以 同时处理的连接数是backlog的1.5倍,很多地方都用5. 7) getsockname 和 getpeername 这两个函数可以与socket关联的地址,getsockname 和 getpeername分别得到自己和对端的地址
    int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen)  
      
    int getpeername(int sockfd , struct sockaddr * peeraddr , socklen_t * addrlen );  

    FROM: http://blog.csdn.net/wind19/article/details/6156339

  • 相关阅读:
    c#类,接口,结构,抽象类介绍 以及抽象和接口的比较
    存储过程基本语法
    有关uploadifive的使用经验
    堆栈的浅析
    JavaScript语言精粹4递归(汉诺塔游戏寻常解)及作用域
    JavaScript语言精粹3异常,扩充类型功能
    有关this,4种调用模式小例子
    JavaScript语言精粹2函数对象,函数字面量,调用
    JavaScript语言精粹1字符串,对象字面量
    JQUERY选择器第一天
  • 原文地址:https://www.cnblogs.com/XACOOL/p/5665613.html
Copyright © 2011-2022 走看看