Winsock版本的“hello world!”

时间:2022-09-16 07:32:16

1.基于TCP协议的“hello world!”

1)服务器端:WSAStartup()->socket()->bind()->listen()->accept()->send()/recv()->closesocket()->WSACleanup().

Winsock版本的“hello world!”Winsock版本的“hello world!”
 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 \r\n",strlen("hello client \r\n")+sizeof(char),NULL);
26 
27     closesocket(clientSock);
28     closesocket(s);
29 
30     WSACleanup();
31     return 0;
32 }
View Code

2)客户端:WSAStartup()->socket()->connect()->recv()/send()->closesocket()->WSACleanup().

Winsock版本的“hello world!”Winsock版本的“hello world!”
 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 \r\n",szBuffer);
24 
25     closesocket(s);
26 
27     WSACleanup();
28     return 0;
29 }
View Code

2.基于UDP协议的“hello world!”

1)服务器端:

Winsock版本的“hello world!”Winsock版本的“hello world!”
 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 \r\n",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 }
View Code

2)客户端:

Winsock版本的“hello world!”Winsock版本的“hello world!”
 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 \r\n",buf);
23 
24     closesocket(s);
25 
26     WSACleanup();
27     return 0;
28 }
View Code

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结构:

Winsock版本的“hello world!”Winsock版本的“hello world!”
1 struct sockaddr{ 
2    u_short sa_family;
3    char sa_data[14];
4 };
View Code

实际使用过程中,结构体是sockaddr_in:

Winsock版本的“hello world!”Winsock版本的“hello world!”
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 };
View Code

成员变量sin_family设置为PF_INET;sin_port设置为端口号;sin_addr结构体中只包含一个公用体:

Winsock版本的“hello world!”Winsock版本的“hello world!”
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 };
View Code

该成员变量为一个整数,一般用函数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);