Winsock网络编程快速入门

转自: http://blog.csdn.net/zhao_yin/article/details/6982382


一、基本知识

 

1、Winsock,一种标准API,一种网络编程接口,用于两个或多个应用程序(或进程)之间通过网络进行数据通信。具有两个版本:

Winsock 1:

Windows CE平台支持。

头文件:WinSock.h

库:wsock32.lib

 

Winsock 2:

部分平台如Windows CE貌似不支持。通过前缀WSA可以区别于Winsock 1版本。个别函数如WSAStartup、WSACleanup、WSARecvEx、WSAGetLastError都属于Winsock 1.1规范的函数;

头文件:WinSock2.h

库:ws2_32.lib

 

mswsock.h用于编程扩展,使用时必须链接mswsock.dll。

 

2、网络协议:

IP (Internet Protocol)  网际协议,无连接协议;

TCP (Transmission Control Protocol)  传输控制协议;

UDP (User Datagram Protocol)  用户数据协议;

FTP (File Transfer Protocol)  文件传输协议;

HTTP (Hypertext Transfer Protocol)  超文本传输协议;

 

3、字节存储顺序:

big_endian:大端存储,存储顺序从高位到低位,地址指向最高有效字节。在网络中将IP和端口指定为多字节时使用大端存储,也称为网络字节顺序(network_byte)。貌似MAC OS使用的是大端存储方式;

 

little_endian:小端存储,存储顺序从低位到高位,地址指向最低有效字节。本地主机存储IP和端口制定的多字节时使用,也称为主机字节顺序(host_byte)。大多数系统都是小端存储;

 

用下面的方式可以检测是否为大端存储:

  1. bool IsBig_endian()  
  2. {  
  3.     unsigned short test = 0x1122;  
  4.     if ( *( (unsigned char*)&test ) == 0x11 )  
  5.     {  
  6.         return true;  
  7.     }   
  8.     else  
  9.     {  
  10.         return false;  
  11.     }  
  12. }  

 

此外有很多函数可以用来进行 主机字节和网络字节之间的转换,如:

u_long htonl( u_long hostlong );

int WSAHtonl( SOCKET s, u_long hostlong, u_long FAR *lpnetlong );

而有时网络IP是点分法表示的,如:192.168.0.1,使用函数 unsigned long inet_addr( const char FAR *cp ); 可以将点分法的IP字符串作为一个网络字节顺序的32位u_long返回。

 

 

二、快速了解

 

1、Winsock初始化:

首先确保包含对应版本的头文件,然后保证链接对应的库文件(可以在代码中使用#pragma comment(lib, "WS2_32"),或在编译器项目属性中链接器->输入->附加依赖项中添加ws2_32.lib);

 通过调用WSAStartup函数来实现加载Winsock库:

  1. int  
  2. WSAAPI  
  3. WSAStartup(  
  4.     IN WORD wVersionRequested,  
  5.     OUT LPWSADATA lpWSAData  
  6.     );  

其中参数wVersionRequested用来指定加载Winsock库的版本,高位字节为次版本,低位字节为主版本,使用宏 MAKEWORD(x,y)来生成一个WORD;

参数lpWSAData是指向WASDATA结构指针,加载的版本库信息将会填充这个结构,详细内容自查。

在使用Winsock后需要释放资源,并取消应用程序挂起的Winsock操作。使用 int WASCleanup();

 

 

2、错误处理:

如果已经加载了Winsock库,则调用Winsock函数出错后,通常会返回SOCKET_ERROR,而通过使用函数 int WSAGetLastError() 可以获得具体信息值,例如:

  1. if ( SOCKET_ERROR == WSACleanup() )  
  2. {  
  3.     cout << "WSACleanup error " << WSAGetLastError() << endl;  
  4.     return 0;  
  5. }  
根据获取错误信息值,可以知道错误原因,并进行相应的处理。
 
 
3、寻址:
想要进行通信就需要知道彼此的地址,一般来说这个地址由IP和端口号来决定。在Winsock中使用SOCKADDR_IN结构来指定地址信息:
  1. struct sockaddr_in {  
  2.         short   sin_family;  
  3.         u_short sin_port;  
  4.         struct  in_addr sin_addr;  
  5.         char    sin_zero[8];  
  6. };  
sin_family字段通常设置为AF_INET,表示Winsock此时正在使用IP地址族;
sin_port用于标示TCP或UDP通信端口,部分端口是为一些服务保留的,如FTP和HTTP使用要注意;
sin_adr字段把地址(例如是IPv4地址)作为一个4字节的量来存储起来,它是u_long类型,且是网络字节顺序的。可以使用inet_addr来处理点分法表示的IP地址;
sin_zero只充当填充项,以使SOCKADDR_IN结构和SOCKADDR结构长度一样。
以下简单的使用SOCKADDR_IN来指定地址:
  1. //创建一个地址  
  2. int serverPort      = 5150;  
  3.   
  4. char FAR serverIP[] = "192.168.1.102"//本机ip,不知道就ipconfig  
  5.   
  6. SOCKADDR_IN serverAddr;  
  7. serverAddr.sin_family   = AF_INET;  
  8. serverAddr.sin_port = htons( serverPort );  
  9. serverAddr.sin_addr.s_addr  = inet_addr( serverIP );  
  10. int serverAddr_size = static_cast<int>( sizeof(serverAddr) );  
有时作为一个连接通信的服务端来说,在设置监听socket的地址结构时sin_addr.s_addr的值可以是htonl( INADDR_ANY ),INADDR_ANY允许将socket绑定到系统中所有可用的接口,以便传到任意接口的连接(端口必须正确)都可以被监听socket接受。
 
 
4、socket套接字:
套接字是通信时为传输提供的句柄,Winsock的操作都是基于套接字实现的。创建一个套接字有socket和WSASocket方法:
  1. SOCKET  
  2. WSAAPI  
  3. socket(  
  4.        IN int af,       //协议的地址族,使用IPv4来描述Winsock,设置为AF_INET  
  5.        IN int type,     //套接字类型,TCP/IP设置为SOCK_STREAM,UDP/IP设置为SOCK_DGRAM  
  6.        IN int protocol      //用于给定地址族和类型具有多重入口的传送限定,TCP设置为IPPROTO_TCP,UDP设置为IPPROTO_UDP  
  7.        );  
如果创建成功,函数会返回一个有效的SOCKET,否则会返回INVALID_SOCKET,可以用WSAGetLastError()函数获得错误信息。
 
 
5、连接通信实现过程:
连结通信是基于TCP/IP实现的,进行数据传输前,通信双方要进行连接。
 
服务端:
初始化Winsock后,创建一个监听socket和一个要接受连接的地址结构;
使用bind将监听socket与地址结构进行关联;
  1. int  
  2. WSAAPI  
  3. bind(  
  4.      IN SOCKET s,               //一个用于监听的socket  
  5.      IN const struct sockaddr FAR * name,   //指向进行绑定的地址结构  
  6.      IN int namelen             //进行绑定的地址结构的大小  
  7.      );  
使用listen将bind成功的监听socket状态设置为监听状态;
  1. int  
  2. WSAAPI  
  3. listen(  
  4.        IN SOCKET s,     //一个用于监听的socket,已经进行bind  
  5.        IN int backlog       //允许挂起连接的队列的最大长度,超过这个长度后,再有连接将会失败  
  6.        );  
 
使用accept接受通过监听socket获取的连接,成功后将返回的新的连接socket进行保存以便数据传输;
  1. SOCKET  
  2. WSAAPI  
  3. accept(  
  4.        IN SOCKET s,         //处于监听模式的socket  
  5.        OUT struct sockaddr FAR * addr,  //指向一个地址结构,用来接受连接后获得对方地址信息  
  6.        IN OUT int FAR * addrlen     //指向一个整数,表示参数2指向地址结构的大小  
  7.        );  
 
 
客户端:
初始化Winsock后,创建一个监听socket和一个要连接的服务器地址结构;
使用connect将socket和服务器地址结构进行初始化连接,成功后将使用socket进行数据传输;
  1. int  
  2. WSAAPI  
  3. connect(  
  4.         IN SOCKET s,            //要建立连接的socket  
  5.         IN const struct sockaddr FAR * name,    //指向保存要建立连接信息的地址结构  
  6.         IN int namelen          //参数2指向地址结构的大小  
  7.         );  
 
 
连接成功后,使用send、recv来进行数据传输;
  1. int  
  2. WSAAPI  
  3. send(  
  4.      IN SOCKET s,       //进行连接的socket  
  5.      IN const char FAR * buf,   //指向发送数据的缓冲区  
  6.      IN int len,        //发送数据的字符数  
  7.      IN int flags       //一个标志位,可以是0、MSG_DONTROUTE、MSG_OOB还可以是他们的或运算结果  
  8.      );         //返回已经发送的数据长度  
  9.   
  10.   
  11. int  
  12. WSAAPI  
  13. recv(  
  14.      IN SOCKET s,       //进行连接的socket  
  15.      OUT char FAR * buf,    //指向接受数据的缓冲区  
  16.      IN int len,        //准备接受数据字节数或缓冲区的长度  
  17.      IN int flags       //可以是0、MSG_PEEK、MSG_OOB还可以是他们的或运算结果  
  18.      );         //返回已接受的数据长度  
 
连接结束后,使用shutdown和closesocket来断开连接和释放资源;
  1. int  
  2. WSAAPI  
  3. shutdown(  
  4.          IN SOCKET s,   //要关闭的socket  
  5.          IN int how //关闭标志:SD_RECEIVE、SD_SEND、SD_BOTH  
  6.          );  
 
 
6、无连接通信实现过程:
无连接通信是基于UDP/IP实现的,UDP不能确保可靠的数据传输,但能将数据发送到多个目标,或者接受多个源的数据。
初始化Winsock后,可以创建socket和用以进行通信任意地址结构;
使用recvfrom通过socket和通信的地址结构接受数据;
使用sendto通过socket和通信的地址结构发送数据;
  1. int  
  2. WSAAPI  
  3. recvfrom(  
  4.          IN SOCKET s,  
  5.          OUT char FAR * buf,  
  6.          IN int len,  
  7.          IN int flags,  
  8.          OUT struct sockaddr FAR * from,  
  9.          IN OUT int FAR * fromlen  
  10.          );  
  11.   
  12. int  
  13. WSAAPI  
  14. sendto(  
  15.        IN SOCKET s,  
  16.        IN const char FAR * buf,  
  17.        IN int len,  
  18.        IN int flags,  
  19.        IN const struct sockaddr FAR * to,  
  20.        IN int tolen  
  21.        );  
 
同样通信结束后,使用shutdown和closesocket来断开连接和释放资源
 
 
上述使用函数都有多个版本,而且相关的一些标志位参数可以提供设置选项,另外,返回的错误处理等也有待于详细研究;
 
 
7、select函数:
 
select()用于确定一个或多个套接口的状态。对每一个套接口,调用者可查询它的可读性、可写性及错误状态信息。
  1. int  
  2. WSAAPI  
  3. select(  
  4.        IN int nfds,         //指集合中所有文件描述符的范围,即所有文件描述符的最大值加1,在Windows中值无所谓。   
  5.        IN OUT fd_set FAR * readfds, //可选指针,指向一组等待可读性检查的套接字。   
  6.        IN OUT fd_set FAR * writefds,    //可选指针,指向一组等待可写性检查的套接字。  
  7.        IN OUT fd_set FAR *exceptfds,    //可选指针,指向一组等待错误检查的套接字。  
  8.        IN const struct timeval FAR * timeout    //select()最多等待时间,对阻塞操作则为NULL。  
  9.        );  
  10.   
  11. //用fd_set结构来表示一组等待检查的套接口。在调用返回时,这个结构存有满足一定条件的套接口组的子集:  
  12.   
  13. typedef struct fd_set {  
  14.     u_int fd_count;               //其中set元素数目  
  15.     SOCKET  fd_array[FD_SETSIZE]; //保存set元素的数组  
  16. } fd_set;  
  17.   
  18. fd_set set;  
  19. FD_ZERO(&set);      /*将set清零使集合中不含任何fd*/     
  20. FD_SET(fd, &set);       /*将fd加入set集合*/     
  21. FD_CLR(fd, &set);       /*将fd从set集合中清除*/     
  22. FD_ISSET(fd, &set);     /*测试fd是否在set集合中*/   
 
select的返回值:
select()调用返回处于就绪状态并且已经包含在fd_set结构中的描述字总数;
如果超时则返回0;否则的话,返回SOCKET_ERROR错误,通过WSAGetLastError获取相应错误代码。
当返回位0时,所有描述符集清0;
当返回为-1时,不修改任何描述符集;
当返回为非0时,在3个描述符集里,依旧是1的位就是准备好的描述符。这也就是为什么,每次用select后都要用FD_ISSET的原因。

 

 

三、简单实践

 
利用上述内容,实现一个基于TCP/IP的连接通信。
 
服务端:
 
//******************************************************************
  1. #include "stdafx.h"  
  2.   
  3. #include <iostream>  
  4.   
  5. #include <WinSock2.h>  
  6.   
  7. #pragma comment(lib, "WS2_32")  
  8.   
  9.   
  10. using namespace std;  
  11.   
  12.   
  13.   
  14. # define REQUEST_BACKLOG 5  
  15.   
  16.   
  17. //******************************  
  18. //好吧不用写这些纠结的函数,就是看着清晰些  
  19. //初始化Winsock  
  20. bool InitWSA( const WORD &wVersion, WSADATA *wsadata )  
  21. {  
  22.     int Ret = 0;  
  23.     if ( ( Ret = WSAStartup( wVersion,wsadata ) ) != 0 )  
  24.     {  
  25.         cout << "WSAStartup failed, error "  << Ret << endl;  
  26.   
  27.         return false;  
  28.     }  
  29.   
  30.     return true;  
  31. }  
  32.   
  33.   
  34. //结束Winsock  
  35. void cleanWSA()  
  36. {  
  37.     if ( WSACleanup() == SOCKET_ERROR )  
  38.     {  
  39.         cout << "WSACleanup failed, error "  << WSAGetLastError() << endl;  
  40.     }  
  41. }  
  42.   
  43.   
  44.   
  45. //IPv4寻址,通过ip填充SOCKADDR_IN结构  
  46. void InitSockAddrByIP( SOCKADDR_IN *pSockAddr, const char FAR *strIP, const INT &nPortID )  
  47. {  
  48.     pSockAddr->sin_family            = AF_INET;  
  49.   
  50.     pSockAddr->sin_port              = htons( nPortID );  
  51.   
  52.     if ( 0 != strlen(strIP) )  
  53.     {  
  54.         pSockAddr->sin_addr.s_addr       = inet_addr( strIP );  
  55.     }  
  56.     else  
  57.     {  
  58.         pSockAddr->sin_addr.s_addr       = htonl( INADDR_ANY );  
  59.     }  
  60. }  
  61.   
  62.   
  63. //bind  
  64. bool bindAddr( const SOCKADDR_IN *pSockAddr, SOCKET *pSocket )  
  65. {  
  66.     int bindResult = bind( *pSocket, (sockaddr *)(pSockAddr), sizeof(*pSockAddr));  
  67.   
  68.     if ( SOCKET_ERROR == bindResult )  
  69.     {  
  70.         cout << "bind error :" << WSAGetLastError() << endl;  
  71.         return false;  
  72.     }   
  73.     return true;  
  74. }  
  75.   
  76.   
  77. //listen  
  78. bool setListener( SOCKET *pSocket, int backlog )  
  79. {  
  80.     int nResult = listen( *pSocket, backlog );  
  81.   
  82.     if ( SOCKET_ERROR == nResult )  
  83.     {  
  84.         cout << "listen error :" << WSAGetLastError() << endl;  
  85.         return false;  
  86.     }   
  87.     return true;  
  88. }  
  89.   
  90.   
  91.   
  92.   
  93.   
  94. //******************************  
  95.   
  96.   
  97. //程序入口  
  98. int _tmain(int argc, _TCHAR* argv[])  
  99. {  
  100.   
  101.     //初始化Winsock  
  102.     WSADATA wsadata;  
  103.     if ( !InitWSA( MAKEWORD(2,2), &wsadata ) )  
  104.     {  
  105.         return 0;  
  106.     }  
  107.   
  108.   
  109.     //指定连接ip地址和服务器口  
  110.   
  111.     SOCKADDR_IN InternetAddr;  
  112.     //char FAR strIP[]  = "198.0.0.0";  
  113.     char FAR strIP[]    = "";  
  114.     INT nPortID         = 5150;  
  115.     InitSockAddrByIP( &InternetAddr, strIP, nPortID );  
  116.   
  117.   
  118.   
  119.     //创建listener_socket  
  120.     SOCKET listener_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );  
  121.     if ( INVALID_SOCKET == listener_socket )  
  122.     {  
  123.         cout << "listener_socket creat failed " << endl;  
  124.         return 0;  
  125.     }  
  126.   
  127.   
  128.     //bind  
  129.     if ( !bindAddr( &InternetAddr, &listener_socket ) )  
  130.     {  
  131.         return 0;  
  132.     }  
  133.   
  134.   
  135.     //监听  
  136.     if ( !setListener( &listener_socket, REQUEST_BACKLOG ) )  
  137.     {  
  138.         return 0;  
  139.     }  
  140.   
  141.     cout << "server started~~~ " << endl;  
  142.   
  143.   
  144.   
  145.     //创建 socket保存结构  
  146.     fd_set fdSocket;  
  147.     FD_ZERO( &fdSocket );  
  148.     FD_SET( listener_socket, &fdSocket );  
  149.   
  150.   
  151.     //查找可读的 socket  
  152.     whiletrue )  
  153.     {  
  154.         fd_set fdSocket_temp;  
  155.         fdSocket_temp = fdSocket;  
  156.           
  157.         fd_set fdRead;  
  158.         fdRead = fdSocket;  
  159.   
  160.         fd_set fdExceptds;  
  161.         fdExceptds = fdSocket;  
  162.   
  163.         int nResult_select = select( 0, &fdRead, NULL, &fdExceptds, NULL );  
  164.   
  165.         if ( 0 < nResult_select )  
  166.         {  
  167.             unsigned int socket_count = fdSocket_temp.fd_count;  
  168.             for ( unsigned int i=0; i< socket_count; i++ )  
  169.             {  
  170.   
  171.                 //可读的  
  172.   
  173.                 if ( FD_ISSET( fdSocket_temp.fd_array[i], &fdRead ) )  
  174.                 {  
  175.                     //找到所有可读连接  
  176.                     if ( fdSocket_temp.fd_array[i] == listener_socket )  
  177.                     {  
  178.                         if ( fdSocket.fd_count < FD_SETSIZE )  
  179.                         {  
  180.   
  181.                           
  182.                             //接受新的连接  
  183.                             SOCKADDR_IN ClientAddr;  
  184.                             int addrlen = static_cast<int>(sizeof(ClientAddr));   //一定要赋值  
  185.   
  186.                             SOCKET newClient_socket = accept( listener_socket, (sockaddr *)&ClientAddr, &addrlen );  
  187.                             if ( INVALID_SOCKET == newClient_socket )  
  188.                             {  
  189.                                 cout << " accept error " << WSAGetLastError() << endl;  
  190.                             }  
  191.                             else  
  192.                             {  
  193.                                 FD_SET( newClient_socket, &fdSocket );  
  194.                                 cout << "find new connect: " << inet_ntoa( ClientAddr.sin_addr ) << endl;  
  195.                             }  
  196.                         }  
  197.   
  198.                         else  
  199.                         {  
  200.                             cout<<"too much connections"<<endl;  
  201.                             continue;  
  202.                         }  
  203.   
  204.                     }   
  205.                     else  
  206.                     {  
  207.   
  208.                         //接收数据  
  209.   
  210.                         char recvbuff[1024];  
  211.                         int  ret = 0;  
  212.   
  213.                         ret = recv( fdSocket_temp.fd_array[i], recvbuff, static_cast<int>( strlen(recvbuff) ), 0 );  
  214.                         if ( 0 < ret )  
  215.                         {  
  216.                             recvbuff[ret] = '\0';  
  217.                             cout << "recv : " << recvbuff << endl;  
  218.                             //回复  
  219.                             char backbuf[1024] = "receive info!";  
  220.                             send( fdSocket_temp.fd_array[i], backbuf, static_cast<int>( strlen(backbuf) ), 0 );  
  221.               
  222.                         }  
  223.                         else  
  224.                         {  
  225.                             //该连接断开  
  226.                             closesocket( fdSocket_temp.fd_array[i] );  
  227.                             FD_CLR( fdSocket_temp.fd_array[i], &fdSocket );  
  228.                         }  
  229.   
  230.                     }  
  231.                       
  232.                 }  
  233.                 else if( fdSocket_temp.fd_array[i] != listener_socket )  
  234.                 {  
  235.                     //该连接断开  
  236.                     closesocket( fdSocket_temp.fd_array[i] );  
  237.                     FD_CLR( fdSocket_temp.fd_array[i], &fdSocket );  
  238.                 }  
  239.   
  240.   
  241.                 if ( FD_ISSET( fdSocket_temp.fd_array[i], &fdExceptds )  &&  (fdSocket_temp.fd_array[i] != listener_socket) )  
  242.                 {  
  243.                     //该连接断开  
  244.                     closesocket( fdSocket_temp.fd_array[i] );  
  245.                     FD_CLR( fdSocket_temp.fd_array[i], &fdSocket );  
  246.                 }  
  247.       
  248.             }//end for  
  249.         }  
  250.   
  251.   
  252.         else if( SOCKET_ERROR == nResult_select )  
  253.         {  
  254.             cout << "select error : " << WSAGetLastError() << endl;  
  255.             return 0;  
  256.         }  
  257.   
  258.   
  259.         Sleep( 50 );    //不要挑战你的机器  
  260.   
  261.     }//end while  
  262.   
  263.   
  264.     closesocket( listener_socket );  
  265.     cleanWSA();  
  266.   
  267.     return 0;  
  268. }  

 

 

 
 
客户端:
 
//******************************************************************
  1. #include "stdafx.h"  
  2.   
  3. #include <WinSock2.h>  
  4.   
  5. #include <iostream>  
  6.   
  7. #pragma comment(lib, "WS2_32")  
  8.   
  9. using namespace std;  
  10.   
  11.   
  12.   
  13.   
  14. int _tmain(int argc, _TCHAR* argv[])  
  15. {  
  16.     int result = 0;  
  17.   
  18.     //初始化winsock  
  19.   
  20.     WSADATA wsadata;  
  21.     result = WSAStartup( MAKEWORD(2,2), &wsadata );  
  22.   
  23.     if ( 0 != result )  
  24.     {  
  25.         cout << "WSAStartup error " << result << endl;  
  26.         return 0;  
  27.     }  
  28.   
  29.     //创建一个地址  
  30.     int serverPort      = 5150;  
  31.   
  32.     char FAR serverIP[] = "192.168.1.102"//本机ip,不知道就ipconfig  
  33.   
  34.     SOCKADDR_IN serverAddr;  
  35.     serverAddr.sin_family       = AF_INET;  
  36.     serverAddr.sin_port         = htons( serverPort );  
  37.     serverAddr.sin_addr.s_addr  = inet_addr( serverIP );  
  38.     int serverAddr_size         = static_cast<int>( sizeof(serverAddr) );  
  39.   
  40.     //创建一个socket  
  41.     SOCKET socket_toServer;  
  42.     socket_toServer = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );  
  43.     if ( INVALID_SOCKET == socket_toServer )  
  44.     {  
  45.         cout << "socket_toServer creat failed " << WSAGetLastError() << endl;  
  46.         return 0;  
  47.     }  
  48.   
  49.       
  50.     //连接  
  51.     result = connect( socket_toServer, (sockaddr *)&serverAddr, serverAddr_size );  
  52.     if ( SOCKET_ERROR == result )  
  53.     {  
  54.         cout << "connect error :" << WSAGetLastError() << endl;  
  55.         return 0;  
  56.     }  
  57.   
  58.       
  59.     char sendbuff[2048];  
  60.     char recvbuff[2048];  
  61.   
  62.     whiletrue )  
  63.     {  
  64.         cout << "input send info:" << endl;  
  65.         cin >> sendbuff;  
  66.   
  67.         int ret = send( socket_toServer, sendbuff, static_cast<int>( strlen(sendbuff) ), 0 );  
  68.         if ( SOCKET_ERROR == ret )  
  69.         {  
  70.             cout << "send error " << WSAGetLastError() <<  endl;  
  71.             break;  
  72.         }  
  73.   
  74.         //处理接受的消息,由于之前没有accept和listen,这里使用recvfrom来接受  
  75.         int nRecv = 0;  
  76.         nRecv = recvfrom( socket_toServer, recvbuff, static_cast<int>( strlen(recvbuff) ), 0, (sockaddr *)&serverAddr, &serverAddr_size );  
  77.         if ( 0 < nRecv )  
  78.         {  
  79.             recvbuff[nRecv] = '\0';  
  80.             cout << "receive : " << recvbuff << endl;  
  81.             cout << "from : " << inet_ntoa( serverAddr.sin_addr ) << endl;  
  82.             cout << " " << endl;  
  83.         }  
  84.     }  
  85.   
  86.   
  87.     //清除各种数据和链接  
  88.   
  89.     closesocket( socket_toServer );  
  90.   
  91.     if ( SOCKET_ERROR == WSACleanup() )  
  92.     {  
  93.         cout << "WSACleanup error " << WSAGetLastError() << endl;  
  94.         return 0;  
  95.     }  
  96.       
  97.   
  98.     return 0;  
  99. }  

 

如题,上述内容只是帮助快速入门,要掌握Winsock还要经过大量的学习和实践。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值