Winsock编程原理——面向连接

Winsock编程原理——面向连接

Windows Sockets使用套接字进行编程,套接字编程是面向客户端/服务器模型而设计的,因此系统中需要客户端和服务器两个不同类型的进程,根据连接类型的不同,对于面向连接的TCP服务和无连接的UDP服务,服务器分别采取不同的处理操作来对客户提供服务。

面向连接

服务器
socket() -> bind() -> listen() -> accept() -> recv()/send() -> closesocket();
创建套接字,绑定IP和端口,侦听,接收连接,收发消息,关闭连接
客户端
socket() -> connet() -> send()/recv() -> closesocket();
创建套接字,连接服务器,发收消息,关闭连接
 
一对一的模式,一个服务器, 一个客户端
 
 1 /*
 2 服务器端代码
 3 */
 4 
 5 #include<Winsock2.h>
 6 #include<stdio.h>
 7 #include<stdlib.h>
 8 #pragma comment(lib,"ws2_32.lib")
 9 #define PORT 5000
10 
11 void main()
12 {
13     int port = PORT;                                    //端口
14     WSADATA wsaData;                                    //存储系统传回的关于Winsock的资料
15     SOCKET sListen, sAccept;                            //套接字
16     int iLen;                                            //客户地址长度
17     int iSend;                                            //发送数据长度
18     char buf[] = "Hello, How are you!";                    //需要发送的信息
19     struct sockaddr_in serv, cliet;                        //服务器、客户的地址
20 
21     if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)        //函数WSAStartup用以打开Winsock
22     {
23         printf("Winsock load failed
");
24         return;
25     }
26 
27     sListen = socket(AF_INET, SOCK_STREAM, 0);            //创建套接字,TCP协议
28     if (sListen == INVALID_SOCKET)                        //socket调用成功返回套接字对象,失败返回INVALID_SOCKET
29     {
30         printf("socket failed:%d
", WSAGetLastError());
31         return;
32     }
33 
34     serv.sin_family = AF_INET;                            //网络中标识不同设备使用的地址类型,对于IP地址,类型是AF_INET
35     serv.sin_port = htons(port);                        //socket对应的端口号
36     serv.sin_addr.s_addr = htonl(INADDR_ANY);            //封装了IP地址
37     if (bind(sListen, (LPSOCKADDR)&serv, sizeof(serv)) == SOCKET_ERROR)        //绑定套接字
38     {
39         printf("bind() failed:%d
", WSAGetLastError());
40         return;
41     }
42 
43     if (listen(sListen, 5) == SOCKET_ERROR)                //监听
44     {
45         printf("listen() failed:%d
", WSAGetLastError());
46         return;
47     }
48 
49     iLen = sizeof(cliet);                                //初始化客户地址长度
50 
51     while (1)                                            //进入循环,等待客户连接请求
52     {
53         sAccept = accept(sListen, (struct sockaddr*)&cliet, &iLen);    //客户端的套接字
54         if (sAccept == INVALID_SOCKET)                    //接受连接请求失败
55         {
56             printf("accept() failed:%d
", WSAGetLastError());
57             break;
58         }
59         //输出客户端IP、端口
60         printf("accept() client IP:[%s], port:[%d]
", inet_ntoa(cliet.sin_addr), ntohs(cliet.sin_port));
61 
62         //给连接的客户发送消息
63         iSend = send(sAccept, buf, sizeof(buf), 0);
64         if (iSend == SOCKET_ERROR)
65         {
66             printf("send() failed:%d
", WSAGetLastError());
67             break;
68         }
69         else if (iSend == 0)
70             break;
71         else
72             printf("send() byte:%d
", send);
73 
74         closesocket(sListen);                            //关闭套接字
75         closesocket(sAccept);                            //关闭套接字
76         WSACleanup();                                    //关闭Winsock
77     }
78     while (1);
79 }
server
 1 /*
 2 客户端程序
 3 */
 4 #include<WinSock2.h>
 5 #include<stdio.h>
 6 #pragma comment(lib,"ws2_32.lib")
 7 #define PORT 5000
 8 #define BUFFER 1024
 9 
10 void main(int argc,char *argv[])
11 {
12     WSADATA wsaData;
13     SOCKET client;
14     int port = PORT;
15     int iLen;                                                //从服务器接收的数据长度
16     char buf[BUFFER];                                        //接收数据的缓冲
17     struct sockaddr_in serv;                                //服务器端地址
18     memset(buf, 0, sizeof(buf));                            //接受数据缓冲区初始化
19 
20     if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)            //函数WSAStartup用以打开Winsock
21     {
22         printf("Winsock load failed
");
23         return;
24     }
25 
26     serv.sin_family = AF_INET;                                //需要连接服务器地址信息,AF_INET表示IP协议
27     serv.sin_port = htons(port);                            //端口
28 //    serv.sin_addr.s_addr = inet_addr(argv[1]);                //IP地址,转为二进制表示的字节IP地址,argv表示cmd下输入的参数
29     serv.sin_addr.s_addr = inet_addr("10.100.211.224");
30     client = socket(AF_INET, SOCK_STREAM, 0);                //客户端套接字,流套接字表示使用TCP协议
31     if (client == INVALID_SOCKET)                            //创建套接字失败
32     {
33         printf("socket() failed:%d
", WSAGetLastError());
34         return;
35     }
36 
37     //连接服务器
38     if (connect(client, (struct sockaddr*)&serv, sizeof(serv)) == INVALID_SOCKET)    
39     {
40         printf("connet() failed:%d
", WSAGetLastError);
41         return;
42     }
43     else
44     {
45         iLen = recv(client, buf, sizeof(buf), 0);            //从服务器接收数据
46         if (iLen = 0)
47             return;
48         else if (iLen == SOCKET_ERROR)
49         {
50             printf("recv() failed:%d
", WSAGetLastError());
51             return;
52         }
53         printf("recv() data from server:%s
", buf);
54     }
55 
56     closesocket(client);                                    //关闭套接字
57     WSACleanup;                                                //关闭Winsock
58 
59 //    system("pause");    //程序暂停
60     printf("press any key to continue");                    //让程序等待
61     while (1);
62 }
client

加入多线程机制,一个服务器,多个客户端  

  1 /*
  2 服务器端代码
  3 */
  4 
  5 #include<Winsock2.h>
  6 #include <windows.h>
  7 #include<stdio.h>
  8 #include<stdlib.h>
  9 #pragma comment(lib,"ws2_32.lib")
 10 #define PORT 5000
 11 class MySocket
 12 {
 13 private:
 14     SOCKET accept;
 15     struct sockaddr_in clientAddr;
 16 public:
 17     MySocket(SOCKET a, struct sockaddr_in c)
 18     {
 19         accept = a;
 20         clientAddr = c;
 21     }
 22     void setAccept(SOCKET a)
 23     {
 24         accept = a;
 25     }
 26     void setClientAddr(struct sockaddr_in c)
 27     {
 28         clientAddr = c;
 29     }
 30     SOCKET getAccept()
 31     {
 32         return accept;
 33     }
 34     struct sockaddr_in getClientAddr()
 35     {
 36         return clientAddr;
 37     }
 38 };
 39 DWORD WINAPI ThreadFuc(LPVOID lparam)
 40 {
 41     MySocket* mSocket = (MySocket*)lparam;                    //接收主线程传来的参数
 42     char buf[] = "Hello, How are you!";                    //需要发送的信息
 43     int iSend = 0;
 44     //输出客户端IP、端口
 45     printf("accept() client IP:[%s], port:[%d]
", inet_ntoa(mSocket->getClientAddr().sin_addr), ntohs(mSocket->getClientAddr().sin_port));
 46     //给连接的客户发送消息
 47     iSend = send(mSocket->getAccept(), buf, sizeof(buf), 0);
 48     if (iSend == SOCKET_ERROR)
 49     {
 50         printf("send() failed:%d
", WSAGetLastError());
 51     }
 52     else if (iSend == 0)
 53         printf("send() failed,no message send successfully
");
 54     else
 55         printf("send() byte:%d
", send);
 56     closesocket(mSocket->getAccept());                            //关闭套接字
 57     return 0;
 58 }
 59 
 60 void main()
 61 {
 62     int port = PORT;                                    //端口
 63     WSADATA wsaData;                                    //存储系统传回的关于Winsock的资料
 64     SOCKET sListen, sAccept;                            //套接字
 65     int iLen;                                            //客户地址长度
 66     struct sockaddr_in serv, cliet;                        //服务器、客户的地址
 67 
 68     if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)        //函数WSAStartup用以打开Winsock
 69     {
 70         printf("Winsock load failed
");
 71         return;
 72     }
 73 
 74     sListen = socket(AF_INET, SOCK_STREAM, 0);            //创建套接字,TCP协议
 75     if (sListen == INVALID_SOCKET)                        //socket调用成功返回套接字对象,失败返回INVALID_SOCKET
 76     {
 77         printf("socket failed:%d
", WSAGetLastError());
 78         return;
 79     }
 80 
 81     serv.sin_family = AF_INET;                            //网络中标识不同设备使用的地址类型,对于IP地址,类型是AF_INET
 82     serv.sin_port = htons(port);                        //socket对应的端口号
 83     serv.sin_addr.s_addr = htonl(INADDR_ANY);            //封装了IP地址
 84     if (bind(sListen, (LPSOCKADDR)&serv, sizeof(serv)) == SOCKET_ERROR)        //绑定套接字
 85     {
 86         printf("bind() failed:%d
", WSAGetLastError());
 87         return;
 88     }
 89 
 90     if (listen(sListen, 5) == SOCKET_ERROR)                //监听
 91     {
 92         printf("listen() failed:%d
", WSAGetLastError());
 93         return;
 94     }
 95 
 96     iLen = sizeof(cliet);                                //初始化客户地址长度
 97 
 98     while (1)                                            //进入循环,等待客户连接请求
 99     {
100         sAccept = accept(sListen, (struct sockaddr*)&cliet, &iLen);    //客户端的套接字
101         if (sAccept == INVALID_SOCKET)                    //接受连接请求失败
102         {
103             printf("accept() failed:%d
", WSAGetLastError());
104             break;
105         }
106         else
107         {
108             MySocket* mSocket = new MySocket(sAccept, cliet);
109             HANDLE thread = CreateThread(NULL, NULL, ThreadFuc, mSocket, NULL, NULL);
110         //    closesocket(sAccept);不能关闭,关闭则不行。
111         }
112     }
113     closesocket(sListen);                            //关闭套接字
114     WSACleanup();                                    //关闭Winsock
115     while (1);
116 }
server
 1 /*
 2 客户端程序
 3 */
 4 #include<WinSock2.h>
 5 #include<stdio.h>
 6 #pragma comment(lib,"ws2_32.lib")
 7 #define PORT 5000
 8 #define BUFFER 1024
 9 
10 void main(int argc, char *argv[])
11 {
12     WSADATA wsaData;
13     SOCKET client;
14     int port = PORT;
15     int iLen;                                                //从服务器接收的数据长度
16     char buf[BUFFER];                                        //接收数据的缓冲
17     struct sockaddr_in serv;                                //服务器端地址
18     memset(buf, 0, sizeof(buf));                            //接受数据缓冲区初始化
19 
20     if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)            //函数WSAStartup用以打开Winsock
21     {
22         printf("Winsock load failed
");
23         return;
24     }
25 
26     serv.sin_family = AF_INET;                                //需要连接服务器地址信息,AF_INET表示IP协议
27     serv.sin_port = htons(port);                            //端口
28     //    serv.sin_addr.s_addr = inet_addr(argv[1]);                //IP地址,转为二进制表示的字节IP地址,argv表示cmd下输入的参数
29     serv.sin_addr.s_addr = inet_addr("192.168.0.21");
30     client = socket(AF_INET, SOCK_STREAM, 0);                //客户端套接字,流套接字表示使用TCP协议
31     if (client == INVALID_SOCKET)                            //创建套接字失败
32     {
33         printf("socket() failed:%d
", WSAGetLastError());
34         return;
35     }
36 
37     //连接服务器
38     if (connect(client, (struct sockaddr*)&serv, sizeof(serv)) == INVALID_SOCKET)
39     {
40         printf("connet() failed:%d
", WSAGetLastError);
41         return;
42     }
43     else
44     {
45         iLen = recv(client, buf, sizeof(buf), 0);            //从服务器接收数据
46         if (iLen = 0)
47             return;
48         else if (iLen == SOCKET_ERROR)
49         {
50             printf("recv() failed:%d
", WSAGetLastError());
51             return;
52         }
53         printf("recv() data from server:%s
", buf);
54     }
55 
56     closesocket(client);                                    //关闭套接字
57     WSACleanup;                                                //关闭Winsock
58 
59     //    system("pause");    //程序暂停
60     printf("press any key to continue");                    //让程序等待
61     while (1);
62 }
client

 

原文地址:https://www.cnblogs.com/starf/p/3623421.html