VS Socket编程
Updated:
以控制台下实现为例子
准备
include<Winsock2.h>
需要在项目中添加依赖项:Ws2_32.lib
代码
此代码实现的功能是服务器端发送数据,客户端连接上服务器端并监听服务器端发送来的数据。
客户端
#include "stdafx.h" #include<Winsock2.h> void _tmain(int argc, _TCHAR* argv[]) { //加载socket动态链接库 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { return; } if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; } //创建客户端套接字 SOCKET client=socket(AF_INET,SOCK_STREAM,0);//流式套接字。(数据报套接字,原套接字) SOCKADDR_IN svr_addr_in;//保存服务器端的地址信息 svr_addr_in.sin_family=AF_INET;//代表TCP/IP协议族 //inet_addr()把字符串变成无符号的长整型。获取服务器地址.0.0.1:本机做服务器,127.0.0.1是服务器的ip地址 svr_addr_in.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); //htons本函数将一个位数从主机字节顺序转换成网络字节顺序,该端口号要与服务器的端口号相同 svr_addr_in.sin_port=htons(6000); while(connect(client,(sockaddr*)&svr_addr_in,sizeof(svr_addr_in))!=0);//链接服务器,等于表示连上服务器 char b[1024]; for(int i=0;;i++) { recv(client,b,sizeof(b),0);//客户端接受文件 printf("%s",b); } closesocket(client);//关闭客户端套接字 WSACleanup();//卸载winsock动态链接库 }
服务器端
#include "stdafx.h" #include<Winsock2.h> void _tmain(int argc, _TCHAR* argv[]) { //加载socket动态链接库 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { return; } if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; } SOCKET svr=socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN svr_addr_in;//创建一个服务器地址结构体,用于保存服务器的信息 svr_addr_in.sin_family=AF_INET;//协议家族 svr_addr_in.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");//htonl(INADDR_ANY);//获取当前机子网卡ip地址 svr_addr_in.sin_port=htons(6000);//设置端口地址 bind(svr,(sockaddr*)&svr_addr_in,sizeof(SOCKADDR_IN));//将socket绑定到本地机地址上面 //把服务器socket设置为监听socket,同时能监听个client客服 listen(svr,5); SOCKADDR_IN client_addr_in;//用于保存客户端的信息 int len=sizeof(SOCKADDR_IN); SOCKET client=accept(svr,(sockaddr*)&client_addr_in,&len);//等待(接受)客户端请求到来 char b[1024]="ss"; for(int i=0;;i++) { send(client,b,sizeof(b),0);//向服务器发送数据 //system("pause"): } closesocket(client);//关闭客户端套接字 closesocket(svr);//关闭服务器套接字 WSACleanup();//卸载socket链接库 return ; }
代码解析
初始化部分
WORD wVersionRequested MAKEWORD( 1, 1 ); WSADATA wsaData; int err= WSAStartup( wVersionRequested, &wsaData );MAKEWORD(a,b)是一个宏,定义如下:
#defineMAKEWORD(a,b)((WORD)(((BYTE)(((DWORD_PTR)(a))&0xff))|((WORD)((BYTE)(((DWORD_PTR)(b))&0xff)))<<8))目的是将两个单字节拼成一个双字节,比如(1,1)会被拼成0x0101. WSADATA为结构体,用于存储socket的内容,定义如下:
typedef struct WSAData { WORD wVersion; WORD wHighVersion; #ifdef _WIN64 unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR * lpVendorInfo; char szDescription[WSADESCRIPTION_LEN+1]; char szSystemStatus[WSASYS_STATUS_LEN+1]; #else char szDescription[WSADESCRIPTION_LEN+1]; char szSystemStatus[WSASYS_STATUS_LEN+1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR * lpVendorInfo; #endif } WSADATA函数
int WSAStartup( __in WORD wVersionRequested, __out LPWSADATA lpWSAData );The**WSAStartup**functioninitiatesuseoftheWinsockDLLbyaprocess. **Parameters** **wVersionRequested** ThehighestversionofWindowsSocketsspecificationthatthecallercanuse.Thehigh-orderbytespecifiestheminorversionnumber;thelow-orderbytespecifiesthemajorversionnumber. **ReturnValue** Ifsuccessful,the**WSAStartup**functionreturnszero.Otherwise,itreturnsoneoftheerrorcodeslistedbelow.TheWSAStartupfunctiondirectlyreturnstheextendederrorcodeinthereturnvalueforthisfunction.Acalltothe[**WSAGetLastError**](ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/winsock/winsock/wsagetlasterror_2.htm)functionisnotneededandshouldnotbeused.
**Errorcode** | **Meaning** |
[**WSASYSNOTREADY**](ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/winsock/winsock/windows_sockets_error_codes_2.htm#winsock.wsasysnotready_2) | Theunderlyingnetworksubsystemisnotreadyfornetworkcommunication. |
[**WSAVERNOTSUPPORTED**](ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/winsock/winsock/windows_sockets_error_codes_2.htm#winsock.wsavernotsupported_2) | TheversionofWindowsSocketssupportrequestedisnotprovidedbythisparticularWindowsSocketsimplementation. |
[**WSAEINPROGRESS**](ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/winsock/winsock/windows_sockets_error_codes_2.htm#winsock.wsaeinprogress_2) | AblockingWindowsSockets1.1operationisinprogress. |
[**WSAEPROCLIM**](ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/winsock/winsock/windows_sockets_error_codes_2.htm#winsock.wsaeproclim_2) | AlimitonthenumberoftaskssupportedbytheWindowsSocketsimplementationhasbeenreached. |
[**WSAEFAULT**](ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/winsock/winsock/windows_sockets_error_codes_2.htm#winsock.wsaefault_2) | ThelpWSADataparameterisnotavalidpointer. |
**Client** | RequiresWindowsVista,WindowsXP,Windows2000Professional,WindowsNTWorkstation,WindowsMe,Windows98,orWindows95. |
**Server** | RequiresWindowsServer2008,WindowsServer2003,Windows2000Server,orWindowsNTServer. |
**Header** | DeclaredinWinsock2.h. |
**Library** | UseWs2_32.lib. |
**DLL** | RequiresWs2_32.dll. |
//创建客户端套接字 SOCKET client=socket(AF_INET,SOCK_STREAM,0);//流式套接字。(数据报套接字,原套接字) SOCKADDR_IN svr_addr_in;//保存服务器端的地址信息 svr_addr_in.sin_family=AF_INET;//代表TCP/IP协议族 //inet_addr()把字符串变成无符号的长整型。获取服务器地址.0.0.1:本机做服务器,127.0.0.1是服务器的ip地址 svr_addr_in.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); //htons本函数将一个位数从主机字节顺序转换成网络字节顺序,该端口号要与服务器的端口号相同 svr_addr_in.sin_port=htons(6000); while(connect(client,(sockaddr*)&svr_addr_in,sizeof(svr_addr_in))!=0);//链接服务器,等于表示连上服务器SOCKET为重定义变量,原始变量类型为_W64unsignedint. 函数
SOCKET WSAAPI socket( __in int af, __in int type, __in int protocol );The**socket**functioncreatesasocketthatisboundtoaspecifictransportserviceprovider. 结构体**SOCKADDR_IN**
struct sockaddr_in{ short sin_family; //Address family (must be AF_INET). unsigned short sin_port; //IP port. struct in_addr sin_addr; //IP address. char sin_zero[8]; //Padding to make structure the same size as SOCKADDR. };The**connect**functionestablishesaconnectiontoaspecifiedsocket.
int connect( __in SOCKET s, //Descriptor identifying an unconnected socket. __in const struct sockaddr* name,//Name of the socket in the sockaddr structure to which the connection should be established. __in int namelen //Length of name, in bytes. );
监听准备
SOCKET svr=socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN svr_addr_in;//创建一个服务器地址结构体,用于保存服务器的信息 svr_addr_in.sin_family=AF_INET;//协议家族 svr_addr_in.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");//htonl(INADDR_ANY);//获取当前机子网卡ip地址 svr_addr_in.sin_port=htons(6000);//设置端口地址 bind(svr,(sockaddr*)&svr_addr_in,sizeof(SOCKADDR_IN));//将socket绑定到本地机地址上面 //把服务器socket设置为监听socket,同时能监听个client客服 listen(svr,5);**bind**函数
bind( IN SOCKET s, __in_bcount(namelen) const struct sockaddr FAR * name, IN int namelen );The**listen**functionplacesasocketinastateinwhichitislisteningforanincomingconnection.
int listen( __in SOCKET s, //Descriptor identifying a bound, unconnected socket. __in int backlog //允许的最多的连接队列 );
发送数据
SOCKADDR_IN client_addr_in;//用于保存客户端的信息 int len=sizeof(SOCKADDR_IN); SOCKET client=accept(svr,(sockaddr*)&client_addr_in,&len);//等待(接受)客户端请求到来 char b[1024]="ss"; for(int i=0;;i++) { send(client,b,sizeof(b),0);//向服务器发送数据 //system("pause"): }
接收数据
char b[1024]; for(int i=0;;i++) { recv(client,b,sizeof(b),0);//客户端接受文件 printf("%s",b); }**send**与**recv**函数的参数表都是
IN SOCKET s, // The descriptor that identifies a connected socket. __out_bcount_part(len, return) __out_data_source(NETWORK) char FAR * buf, // The buffer for incoming data. IN int len,// The length, in bytes, of the buf parameter. IN int flags //A pointer to flags that influences the behavior of this function. See remarks below.
善后处理
closesocket(client);//关闭客户端套接字 closesocket(svr);//关闭服务器套接字 WSACleanup();//卸载winsock动态链接库