WinSock是Windows环境下的网络编程接口,它最初是基于Unix环境下的BSD Socket,是一个与网络协议无关的编程接口。WinSock包含两个主要版本,即WinSock1和WinSock2,在vs2010环境下,一般使用WinSock 2.2实现网络通讯的功能。编程
一、Socket接口启动
须要引入头文件winsock2.h
及库文件ws2_32.lib
服务器
#include <winsock2.h> #pragma comment(lib,"ws2_32.lib") WSADATA wsadata; if(WSAStartup(MAKEWORD(2,2),&wsadata)!=0) { cout<<"Init error"<<endl; return -1; }
WSAStartup
函数原型以下:int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData)
(1)wVersionRequested
:Socket接口版本号,例如2.2版本(MAKEWORD(2,2)
),高位字节存储副版本号,低位字节存储主版本号;
(2)lpWSAData
:指向WSADATA
结构体的指针,WSADATA
结构体返回Socket信息;
若是上面函数执行成功,则返回0,不然能够经过WSAGetLastError()
查看错误代码。例如:WSAEINVAL
表示指定的Windows Socket版本不被该DLL支持。网络
二、IP地址的表示形式
对普通用户而言,IP地址使用点分法表示("192,168.0.1"字符串),但在计算机中不会使用这种方式,由于这样会浪费存储空间。实际上,计算机使用长整型存储IP地址,分为网络字节序和主机字节序。
(1)网络字节序
在网络传输过程当中,IP地址保存为32位二进制,TCP/IP规定,在低位存储地址中保存数据的高位字节,这种存储顺序称为网络字节顺序,因此数据的传输由高位至低位进行的。不一样网络设备和操做系统在发送数据以前都须要将二进制数据转为网络字节序。
(2)IP地址结构体
通用结构socket
struct sockaddr { unsigned short sa_family; char sa_data[14]; };
经常使用结构函数
struct sockaddr_in { short int sin_family; unsigned short int sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; };
struct in_addr
就是32位IP地址。操作系统
struct in_addr { union { struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { u_short s_w1,s_w2; } S_un_w; u_long S_addr; } S_un; #define s_addr S_un.S_addr };
使用inet_addr
和inet_ntoa
这两个函数能够实现点分IP地址字符串和网络字节序IP地址之间的转换。unsigned long inet_addr(const char *cp)
:点分字符串->s_addr
char FAR * inet_ntoa(struct in_addr in)
:in_addr(sin_addr)
->点分字符串指针
(3)主机字节序
可使用htonl()
,htons()
,ntohl()
,ntohs()
这四个函数来实现主机字节顺序和网络字节顺序的转换。code
三、服务器端通讯流程
(1)建立服务器套接字server
server=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
指定IP地址族、SOCKET类型,协议,返回SOCKET接口
(2)绑定本地端口、IP
sockaddr_in sAddr; sAddr.sin_family=AF_INET; sAddr.sin_port=htons(9000); sAddr.sin_addr.S_un.S_addr=htonl(ADDR_ANY); bind(server,(sockaddr*)&sAddr,sizeof(sAddr));
(3)监听等待链接
listen(server,5);
(4)接收链接,返回Socket
sockaddr_in cAddr; int len=sizeof(cAddr); client=accept(server,(sockaddr*)&cAddr,&len);
(5)接收数据
ZeroMemory(buf,BUF_SIZE); recv(client,buf,BUF_SIZE,0);
buf
为缓冲区,BUF_SIZE
是缓冲区的大小;ZeroMemory
函数将缓冲区置0,替代memset
函数。
(6)发送数据
send(client,buf,strlen(buf),0);
在接收过程当中接收大小写成缓冲区大小,发送时写成发送的数据大小!
四、客户端通讯流程
(1)建立客户端套接字
client=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
(2)链接服务器
cAddr.sin_port=htons(9000); cAddr.sin_family=AF_INET; cAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); retVal=connect(client,(sockaddr*)&cAddr,sizeof(cAddr));
(3)发送数据/接收数据
同服务器端
五、清理
(1)shutdown
禁止制定的Socket上发送和接收数据int shutdown(SOCKET s,int how)
参数s
表示要关闭的Socket,当参数how
被设置为SD_RECEIVE
时,不容许再次调用recv
接收数据,设置为SD_SEND
时,不容许再次调用send
发送数据,设置为SD_BOTH
时,不容许发送和接受数据。
(2)closesocket
(3)WSACleanup