zoukankan      html  css  js  c++  java
  • 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; 
      }

      

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 数的统计
    Java实现 蓝桥杯VIP 算法训练 和为T
    Java实现 蓝桥杯VIP 算法训练 友好数
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 暗恋
    Java实现 蓝桥杯VIP 算法训练 暗恋
    测试鼠标是否在窗口内,以及测试鼠标是否在窗口停留
    RichEdit 各个版本介绍
  • 原文地址:https://www.cnblogs.com/xiehy/p/1705190.html
Copyright © 2011-2022 走看看