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 }

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 }
加入多线程机制,一个服务器,多个客户端

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 }

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 }