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; 
  }

 

  

你可能感兴趣的:(socket)