1.基于TCP协议的“hello world!”
1)服务器端:WSAStartup()->socket()->bind()->listen()->accept()->send()/recv()->closesocket()->WSACleanup().
1 #include <WinSock2.h> 2 #pragma comment (lib,"ws2_32") 3 4 int main() 5 { 6 WSADATA wsaData; 7 WSAStartup(MAKEWORD(2,2),&wsaData); 8 9 SOCKET s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); 10 11 sockaddr_in sockaddr; 12 sockaddr.sin_family=PF_INET; 13 sockaddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); 14 sockaddr.sin_port=htons(827); 15 16 bind(s,(SOCKADDR*)&sockaddr,sizeof(SOCKADDR)); 17 18 listen(s,1); 19 20 SOCKADDR clientAddr; 21 int nSize=sizeof(SOCKADDR); 22 SOCKET clientSock; 23 clientSock=accept(s,(SOCKADDR*)&clientAddr,&nSize); 24 25 send(clientSock,"hello client ",strlen("hello client ")+sizeof(char),NULL); 26 27 closesocket(clientSock); 28 closesocket(s); 29 30 WSACleanup(); 31 return 0; 32 }
2)客户端:WSAStartup()->socket()->connect()->recv()/send()->closesocket()->WSACleanup().
1 #include <stdio.h> 2 #include <WinSock2.h> 3 #pragma comment (lib,"ws2_32") 4 5 int main() 6 { 7 WSADATA wsaData; 8 WSAStartup(MAKEWORD(2,2),&wsaData); 9 10 SOCKET s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); 11 12 sockaddr_in sockAddr; 13 sockAddr.sin_family=PF_INET; 14 sockAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); 15 sockAddr.sin_port=htons(827); 16 17 connect(s,(SOCKADDR*)&sockAddr,sizeof(SOCKADDR)); 18 19 char szBuffer[MAXBYTE]={0}; 20 21 recv(s,szBuffer,MAXBYTE,NULL); 22 23 printf("szBuffer=%s ",szBuffer); 24 25 closesocket(s); 26 27 WSACleanup(); 28 return 0; 29 }
2.基于UDP协议的“hello world!”
1)服务器端:
1 #include <WinSock2.h> 2 #include <stdio.h> 3 #pragma comment (lib,"ws2_32") 4 5 int main() 6 { 7 WSADATA wsaData; 8 WSAStartup(MAKEWORD(2,2),&wsaData); 9 10 SOCKET s=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); 11 12 sockaddr_in sockAddr; 13 sockAddr.sin_family=PF_INET; 14 sockAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); 15 sockAddr.sin_port=htons(827); 16 17 bind(s,(SOCKADDR*)&sockAddr,sizeof(SOCKADDR)); 18 19 sockaddr_in clientAddr; 20 int len=sizeof(sockaddr_in); 21 char buf[MAXBYTE]={0}; 22 recvfrom(s,buf,MAXBYTE,0,(SOCKADDR*)&clientAddr,&len); 23 printf("%s ",buf); 24 25 sendto(s,"hello world client",strlen("hello world client")+sizeof(char),0,(SOCKADDR*)&clientAddr,sizeof(SOCKADDR)); 26 27 closesocket(s); 28 29 WSACleanup(); 30 return 0; 31 }
2)客户端:
1 #include <Winsock2.h> 2 #include <stdio.h> 3 #pragma comment (lib,"ws2_32") 4 5 int main() 6 { 7 WSADATA wsaData; 8 WSAStartup(MAKEWORD(2,2),&wsaData); 9 10 SOCKET s=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); 11 12 sockaddr_in sockAddr; 13 sockAddr.sin_family=PF_INET; 14 sockAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); 15 sockAddr.sin_port=htons(827); 16 17 sendto(s,"hello world server",strlen("hello world server")+sizeof(char),0,(SOCKADDR*)&sockAddr,sizeof(SOCKADDR)); 18 sockaddr_in clientAddr; 19 int len=sizeof(sockaddr_in); 20 char buf[MAXBYTE]={0}; 21 recvfrom(s,buf,MAXBYTE,0,(SOCKADDR*)&clientAddr,&len); 22 printf("%s ",buf); 23 24 closesocket(s); 25 26 WSACleanup(); 27 return 0; 28 }
3.Winsock的相关函数:
1)初始化ws2_32.dll的函数:int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);
参数说明:1> wVersionRequested:Windows Sockets API提供的调用方可使用的最高版本号。
2> lpWSAData:指向WSADATA结构的指针,用来接收Windows Sockets实现的细节。
2)释放ws2_32.dll的函数:int WSACleanup(void);
3)创建套接字:SOCKET socket(int af,int type,int protocol);
参数说明:1> af:指定应用程序使用的通信协议簇,对于TCP/IP协议簇,该参数始终为PF_INET。
2> type:指定套接字的类型,流套接字为SOCK_STREAM,为TCP协议使用;数据包套接字为SOCK_DGRAM,为UDP协议使用。
3> protocol:指定应用程序所使用的通信协议。TCP:IPPROTO_TCP; UDP:IPPROTO_UDP。
4)关闭套接字:int closesocket(SOCKET s);
参数说明:s:套接字描述符。
5)绑定IP地址和端口号:int bind(SOCKET s,const struct sockaddr FAR *name,int namelen);
参数说明:1> s;指定待绑定的Socket描述符。
2> name:指定一个sockaddr结构:
1 struct sockaddr{ 2 u_short sa_family; 3 char sa_data[14]; 4 };
实际使用过程中,结构体是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设置为PF_INET;sin_port设置为端口号;sin_addr结构体中只包含一个公用体:
1 struct in_addr{ 2 union{ 3 struct { u_char s_b1, s_b2, s_b3, s_b4;} S_un_b; 4 struct { u_short s_w1, s_w2; } S_un_w; 5 u_long S_addr; 6 }S_un; 7 };
该成员变量为一个整数,一般用函数inet_addr()把字符串形式的IP地址转换为unsigned long整型的整数值。
3> namelen:指定name缓冲区的长度。
6)监听端口:int listen(SOCKET s,int backlog);
参数说明:1> s:使套接字s处于监听状态。
2> backlog:为s维护一个客户连接请求队列。
7)接受请求:SOCKET accept(SOCKET s,struct sockaddr FAR *addr,int FAR *addrlen);
参数说明:1> s:指定处于监听状态的套接字。
2> addr:用来返回新创建的套接字的地址。
3> addrlen:addr的长度。
8)连接:int connect(SOCKET s,const struct sockaddr FAR *name,int namelen);
参数说明:1> s:客户端创建的套接字。
2> name:该结构中包含了服务器端中的IP地址和端口号。
3> namelen:指定name缓冲区的长度。
9)基于TCP的发送函数:int send(SOCKET s,const char FAR *buf,int len,int flags);
参数说明:1> s:指定发送端套接字描述符。
2> buf:指明一个存放应用程序要发送数据的缓冲区。
3> len:指明实际要发送的数据的字节数。
4> flags:一般设置为0。
10)基于TCP的接收函数:int recv(SOCKET s,char FAR *buf,int len,int flags);
参数说明:1> s:指定接收端套接字描述符。
2> buf:指定一个存放接收到的数据的缓冲区。
3> len:指定缓冲区长度。
4> flags:一般设置为0。
11)基于UDP的发送函数:int sendto(SOCKET s,const char FAR *buf,int len,int flags,const struct sockaddr FAR *to,int tolen);
12)基于UDP的接收函数:int sendto(SOCKET s,char FAR *buf,int len,int flags,struct sockaddr FAR *from,int FAR *fromlen);
13)数据存储的字节顺序:本地字节顺序根据CPU架构的不同可能是小尾方式,也可能是大尾方式,如在x86CPU架构上使用小尾顺序,即高位存放高字节,低位存放低字节。而网络字节顺序一定是大尾方式。
本地字节顺序转换为网络字节顺序的函数:u_short htons(u_short hostshort); u_long htonl(u_long hostlong);
网络字节顺序转换为本地字节顺序的函数:u_short ntohs(u_short netshort); u_long ntohl(u_long netlong);