• Socket 编程


    服务器端:

      typedef unsigned short WORD

      1.得到Socket版本号

        WORD MAKEWORD(BYTE bLow,BYTE bHigh);

      2.启动Socket,为Socket做准备

        int WSAStartup(WORD wVersionRequested,  LPWSADATA lpWSAData);

        使用Socket的程序在使用Socket之前必须调用WSAStartup函数。

        该函数的第一个参数指明程序请求使用的Socket版本,其中高位字节指明副版本、低位字节指明主版本;

      操作系统利用第二个参数返回请求的Socket的版本信息。

        当一个应用程序调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的Socket库,

      然后绑定找到的Socket库到该应用程序中。以后应用程序就可以调用所请求的Socket库中的其它Socket

      函数了。该函数执行成功后返回0。  

      3.释放系统资源

         int WSACleanup (void);
           应用程序在完成对请求的Socket库的使用后,要调用WSACleanup函数来解除与Socket库的绑定并

      且释放Socket库所占用的系统资源。

      4.建立Socket

        SOCKET socket(int af, int type, int protocol);  

          应用程序调用socket函数来创建一个能够进行网络通信的套接字。

        第一个参数指定应用程序使用的通信协议的协议族,af一般置为AF_INET;

        第二个参数type为协议的Socket类型,常用的有3种:SOCK_STREAM、SOCK_DGRAM和SOCK_RAW。

          SOCK_STREAM对应于TCP。

          SOCK_DGRAM对应于UDP。

          SOCK_RAW称为原始Socket,可以读写ICMP、IGMP、IP报文。前两种类型使用得最多。

        第三个参数protocol指定所使用的协议。对于SOCK_STREAM、SOCK_DGRAM两种类型的Socket,该参

        数为0,对于原始Socket才需要指定具体的协议。

        接口用例如下:

        SOCKET  ServerSocket;

        ServerSocket = socket(AF_INET,SOCK_STREAM,0);

      5.清除Socket

        int closesocket(SOCKET  ServerSocket);  

        closesocket函数用来关闭一个描述符为ServerSocket套接字。

      6.bind

         int bind(SOCKET ServerSocket, const struct sockaddr FAR *name, int namelen);

         当创建了一个Socket以后,套接字数据结构中有一个默认的IP地址和默认的端口号。一个服务程序

      必须调用bind函数来给其绑定一个IP地址和一个特定的端口号。客户程序一般不必调用bind函数来为其Socket绑定IP地址和端口号。

        该函数的第一个参数指定待绑定的Socket描述符;第二个参数指定一个sockaddr结构,其结构是:

               struct sockaddr

        { 
            short          sin_family;
                u_short       sin_port;
                struct  in_addr   sin_addr;
                char           sin_zero[8];

        }     

        其中sin_family置AF_INET;sin_port指明端口号;sin_addr结构体中只有一个唯一的字段s_addr,表示IP地址,该字段是一个整数,

      一般用函数inet_addr()把字符串形式的IP地址转换成unsigned long型的整数值后再置给s_addr。有的服务器是多宿主机,至少有两个网卡,

      那么运行在这样的服务器上的服务程序在为其Socket绑定IP地址时可以把htonl(INADDR_ANY)置给s_addr,这样做的好处是不论哪个网段上

      的客户程序都能与该服务程序通信.

        如果只给运行在多宿主机上的服务程序的Socket绑定一个固定的IP地址,那么就只有与该IP地址处于同一个网段上的客户程序才能与该服务程序通信。

        我们用0来填充sin_zero数组,目的是让sockaddr_in结构的大小与sockaddr结构的大小一致。下面是一个bind函数调用的例子:  

         struct sockaddr_in saddr;
          saddr.sin_family = AF_INET;
          saddr.sin_port = htons(8888);
          saddr.sin_addr.s_addr = htonl(INADDR_ANY);
          bind(ServerSocket,(struct sockaddr *)&saddr,sizeof(saddr));     

      7.listen

        int listen( SOCKET ServerSocket, int backlog );

        服务程序可以调用listen函数使其流套接字ServerSocket处于监听状态。处于监听状态的流套接字ServerSocket将维护一个客户连接请求队列,

      该队列最多容纳backlog个客户连接请求。假如该函数执行成功,则返回0;如果执行失败,则返回SOCKET_ERROR。 

       8.accept

         SOCKET accept(SOCKET ServerSocket, struct sockaddr FAR *addr, int FAR *addrlen);

         服务程序通过accept()得到一个新的套接字,这个新的套接字是服务端和客户端通信的通道.如果连接成功,就返回新创建

      的套接字的描述符,以后与客户端套接字交换数据的就是新创建的套接字;如果失败就返回INVALID_SOCKET。

        该函数的第一个参数指定处于监听状态的流套接字;操作系统利用第二个参数来返回新创建的套接字的地址结构;操作系统

      利用第三个参数来返回新创建的套接字的地址结构的长度。下面是一个调用accept的例子:

        struct sockaddr_in   NewSocketAddr;

        SOCKET        NewSocket;
            int           NewAddrLen;
            addrlen=sizeof(NewSocketAddr);
            NewSocket =accept(ServerSocket,(struct sockaddr *)&NewSocketAddr,&NewSocketAddr);  

       9.recv

         int recv(SOCKET NewSocket, char FAR *buf,  int len, int flags);      

         不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。该函数的第一个参数指定接收端套接字描述符;

      第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;第三个参数指明buf的长度;第四个参数一般置0。

         注:所有和发送及接收数据相关的缓冲区(buffer)都是char类型(一个char代表一个Byte),这样无论是二进制数据或者是字

      符串文本都可以被缓冲区所容纳。

       10.send

         int send(SOCKET NewSocket,const char FAR *buf, int len,int flags);

        不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,

      而服务器则通常用send函数来向客户程序发送应答。该函数的第一个参数指定发送端套接字描述符;第二个参数指明一个存放应用

      程序要发送数据的缓冲区;第三个参数指明实际要发送的数据的字节数;第四个参数一般置0。  

         注:所有和发送及接收数据相关的缓冲区(buffer)都是char类型(一个char代表一个Byte),这样无论是二进制数据或者是字

      符串文本都可以被缓冲区所容纳。

              

     客户端:

      1.得到Socket版本号

        WORD MAKEWORD(BYTE bLow,BYTE bHigh);

      2.启动Socket,为Socket做准备

        int WSAStartup(WORD wVersionRequested,  LPWSADATA lpWSAData);

        使用Socket的程序在使用Socket之前必须调用WSAStartup函数。

        该函数的第一个参数指明程序请求使用的Socket版本,其中高位字节指明副版本、低位字节指明主版本;

      操作系统利用第二个参数返回请求的Socket的版本信息。

        当一个应用程序调用WSAStartup函数时,操作系统根据请求的Socket版本来搜索相应的Socket库,

      然后绑定找到的Socket库到该应用程序中。以后应用程序就可以调用所请求的Socket库中的其它Socket

      函数了。该函数执行成功后返回0。  

      3.释放系统资源

         int WSACleanup (void);
           应用程序在完成对请求的Socket库的使用后,要调用WSACleanup函数来解除与Socket库的绑定并

      且释放Socket库所占用的系统资源。

      4.建立Socket

        SOCKET socket(int af, int type, int protocol);  

          应用程序调用socket函数来创建一个能够进行网络通信的套接字。

        第一个参数指定应用程序使用的通信协议的协议族,af一般置为AF_INET;

        第二个参数type为协议的Socket类型,常用的有3种:SOCK_STREAM、SOCK_DGRAM和SOCK_RAW。

          SOCK_STREAM对应于TCP。

          SOCK_DGRAM对应于UDP。

          SOCK_RAW称为原始Socket,可以读写ICMP、IGMP、IP报文。前两种类型使用得最多。

        第三个参数protocol指定所使用的协议。对于SOCK_STREAM、SOCK_DGRAM两种类型的Socket,该参

        数为0,对于原始Socket才需要指定具体的协议。

        接口用例如下:

        SOCKET  ClientSocket;

        ClientSocket = socket(AF_INET,SOCK_STREAM,0);

      5.清除Socket

        int closesocket(SOCKET  ClientSocket);  

        closesocket函数用来关闭一个描述符为ClientSocket套接字。

       

      6.connect

        int connect(SOCKET ClientSocket, const struct sockaddr FAR *name,  int namelen);               

        客户端调用connect与服务器进行连接.  如果连接成功,connect返回0;如果失败则返回SOCKET_ERROR。

        下面是一个例子:
            struct sockaddr_in daddr;
            memset((void *)&daddr,0,sizeof(daddr));
            daddr.sin_family=AF_INET;
            daddr.sin_port=htons(8888);
            daddr.sin_addr.s_addr= inet_addr("192.168.1.14");
            connect(ClientSocket,(struct sockaddr *)&daddr,sizeof(daddr));        

             

      7.send

         int send(SOCKET ClientSocket,const char FAR *buf, int len,int flags);

        不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,

      而服务器则通常用send函数来向客户程序发送应答。该函数的第一个参数指定发送端套接字描述符;第二个参数指明一个存放应用

      程序要发送数据的缓冲区;第三个参数指明实际要发送的数据的字节数;第四个参数一般置0。 

         注:所有和发送及接收数据相关的缓冲区(buffer)都是char类型(一个char代表一个Byte),这样无论是二进制数据或者是字

      符串文本都可以被缓冲区所容纳。

           

      8.recv

         int recv(SOCKET ClientSocket, char FAR *buf,  int len, int flags);      

         不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。该函数的第一个参数指定接收端套接字描述符;

      第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;第三个参数指明buf的长度;第四个参数一般置0。

         注:所有和发送及接收数据相关的缓冲区(buffer)都是char类型(一个char代表一个Byte),这样无论是二进制数据或者是字

      符串文本都可以被缓冲区所容纳。

    接口应用时序图 

     

    代码示例

      /****************************************************************************************/

      /*                                                            服务器端                                                */

      /****************************************************************************************/
      void *SocketTaskCallback(void *arg)
      {
         WORD       wVersionRequested;
         WSADATA     wsaData;

         SOCKET       sockconn;

         SOCKADDR_IN   socketadd;
         SOCKADDR_IN   sockclient;

         char   getData[RECEIVE_MAX_LENGTH];
         char   sendData[SEND_MAX_LENGTH];

           int     receive_len = 0;
         int     err;
         int     len;

         wVersionRequested = MAKEWORD( 1, 1 );

         err = WSAStartup( wVersionRequested, &wsaData );
         if ( err != 0 ) 
         {
            DEBUG("Start up fail.\n");
            return NULL;
         }

         if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
         {
               WSACleanup();
            DEBUG("Version check fail.\n");
              return NULL; 
         }

         // 建立套接字    
         socksrv = socket(AF_INET,SOCK_STREAM,0);

         // 绑定
         socketadd.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
         socketadd.sin_family = AF_INET;
         socketadd.sin_port = htons(port);
         if( SOCKET_ERROR == bind(socksrv,(SOCKADDR*)&socketadd,sizeof(SOCKADDR)) )
         {
               DEBUG("bind err\n");
               Mux_ClearSocket();
         }

         // 监听
         if( SOCKET_ERROR == listen(socksrv,5) )
         {
               DEBUG("listen err");
               Mux_ClearSocket();
         }

     
         while(!done)
         {
             // 连接套节字
            sockconn = accept(socksrv,(SOCKADDR*)&sockclient,&len);
            if(INVALID_SOCKET == sockconn )
            {
               DEBUG("accept err\n");
               Mux_ClearSocket();
            }

           //接收

            memset(getData, 0, RECEIVE_MAX_LENGTH);
            receive_len = recv(sockconn,getData,RECEIVE_MAX_LENGTH,0);
            Mux_IniFileUpdata(getData,receive_len);
            DEBUG("%s\n",getData);
      
            //发送

            sprintf(sendData,"%s","update ok!");

            if( SOCKET_ERROR == send(sockconn,sendData,strlen(sendData)+1,0) )
            {
               DEBUG("send err\n");
               Mux_ClearSocket();
            }

            closesocket(sockconn);
         }

         return (void*)NULL; 
      }

      /****************************************************************************************/

      /*                                                            客户端                                                     */

      /****************************************************************************************/

      int SocketClientCode(int argc, const char **argv)
      {
         WORD        wVersionRequested;
         WSADATA      wsaData;
         SOCKET       ClientSocket;
         SOCKADDR_IN   socketadd;
         char    getData[RECEIVE_MAX_LENGTH];
         char    sendData[SEND_MAX_LENGTH]; 
         int    SocketResult;
         int    receive_len;
         int     err,len;


         //获取要发送的数据
         memset(sendData, 0, SEND_MAX_LENGTH);
         if (!doargs(argc, argv,sendData))
         {
            return ERR;
         }

         wVersionRequested = MAKEWORD( 1, 1 );
         err = WSAStartup( wVersionRequested, &wsaData );
         if ( err != 0 ) 
         {
            DEBUG("Start up fail.\n");
            return ERR;
         }
         if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
         {
                WSACleanup();
            DEBUG("Version check fail.\n");
              return ERR; 
         }

         // 建立套接字    
         ClientSocket = socket(AF_INET,SOCK_STREAM,0);

         //连接套接字
         socketadd.sin_family = AF_INET; 
         socketadd.sin_port = htons(port);
         socketadd.sin_addr.S_un.S_addr = inet_addr("192.168.1.14"); 
         len = sizeof(SOCKADDR);
         SocketResult = connect(ClientSocket,(SOCKADDR*)&socketadd,len);
         if(INVALID_SOCKET == SocketResult )
         {
            DEBUG("connect err\n");
            Client_ClearSocket();
         };

         //发送
         if( SOCKET_ERROR == send(ClientSocket,sendData,SEND_MAX_LENGTH,0) )
         {
            DEBUG("send err\n");
            Client_ClearSocket();
         }
         else
         {
            //接收
            memset(getData, 0, RECEIVE_MAX_LENGTH);
            receive_len = recv(ClientSocket,getData,RECEIVE_MAX_LENGTH,0);
            DEBUG("%s\n",getData);
            hxxm_mesgparse_client(getData,receive_len);
         }
     
         closesocket(ClientSocket);
     
         return OK; 
      }

      

  • 相关阅读:
    div 水平居中 内容居左
    net core 踩坑记录
    正向代理和反向代理
    NOIP2013 | 货车运输
    【转载】字符串Hash & 【题解】好文章
    cqyz oj | 帮助Jimmy | DAG图
    cqyz oj | 猜序列
    转载 | 原码, 反码, 补码 详解
    cqyz oj | 有线电视网
    cqyz oj | 罕见的秩序 | 拓扑排序
  • 原文地址:https://www.cnblogs.com/xiehy/p/1705190.html
Copyright © 2020-2023  润新知