网络编程
网络编程--客户端和服务器端
- 客户端和服务器端实现连接和通信
服务器端:
通过sock套接字进行连接通信
#include<WinSock2.h>
#include<Windows.h>
#include<iostream>
#include<WS2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
int main()
{
//初始化网络环境
WSADATA date{ 0 };
WSAStartup(MAKEWORD(2, 2), &date);//WSAStartup 函数通过进程启动 Winsock DLL 的使用
//创建socket
SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//绑定socket的端口号IP地址
sockaddr_in severaddr{ 0 };
severaddr.sin_family = AF_INET;
severaddr.sin_port = htons(8888);
inet_pton(AF_INET, "127.0.0.1", &severaddr.sin_addr);
bind(server, (SOCKADDR*)&severaddr, sizeof(severaddr));
//监听
listen(server, SOMAXCONN);
//会话
sockaddr_in clientaddr{ 0 };
int size = sizeof(clientaddr);
while (1)
{
//获取客户端socket
printf("————等待客户端连接————");
SOCKET client = accept(server, (SOCKADDR*)&clientaddr, &size);
char buff[0x100]{ 0 };
recv(client, buff, 0x00, 0);
printf("客户端发送:%s\n", buff);
send(client, "你还有什么请求?", 16, 0);
}
return 0;
}
客户端:
#include<WinSock2.h>
#include<Windows.h>
#include<iostream>
#include<WS2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
int main()
{
//初始化网络环境
WSADATA date{ 0 };
WSAStartup(MAKEWORD(2, 2), &date);//WSAStartup 函数通过进程启动 Winsock DLL 的使用
//创建socket
SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//绑定socket的端口号IP地址
sockaddr_in severaddr{ 0 };
severaddr.sin_family = AF_INET;
severaddr.sin_port = htons(8888);
inet_pton(AF_INET, "127.0.0.1", &severaddr.sin_addr);
int result = connect(client, (SOCKADDR*)&severaddr, sizeof(severaddr));
if (result)
{
printf("连接失败");
return 0;
}
printf("正在建立连接");
send(client, "dadadaddadada\n", 24, 0);
char buff[0x100]{ 0 };
recv(client, buff, 0x100, 0);
system("pause");
return 0;
}
- 上面的结果只能实现的是1对1,服务器和客户端进行单独的对话,那么我们要怎么样创建的是一个多人聊天的呢?
我们通过建立线程的形式,将每一个客户端与服务器进行会话的socket通过STL中的vector容器以数组的形式进行存储,通过回调函数proc来实现我们的多人聊天对话
服务器:
#include<WinSock2.h>
#include<Windows.h>
#include<iostream>
#include<WS2tcpip.h>
#include<vector>
using std::vector;
vector<SOCKET> client_chat;
#pragma comment(lib,"ws2_32.lib")
DWORD WINAPI Chat_fun(
LPVOID lpParameter
)
{
int recvSize = 0;
char buff[0x100]{ 0 };
SOCKET client = (SOCKET)lpParameter;
while (
(recvSize = recv(client, buff, 0x100, 0)) > 0
)
{
for (int i = 0; i < client_chat.size(); i++)
{
if (client_chat[i] != client)
{
send(client_chat[i], buff, recvSize, 0);
}
}
}
for (int i = 0; i < client_chat.size(); i++)
{
if (client_chat[i] == client)
{
closesocket(client);
client_chat.erase(client_chat.begin() + i);
printf("客户端%u断开了连接\n", client);
}
}
return 0;
}
int main()
{
//初始化网络环境
WSADATA date{ 0 };
WSAStartup(MAKEWORD(2, 2), &date);//WSAStartup 函数通过进程启动 Winsock DLL 的使用
//创建socket
SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//绑定socket的端口号IP地址
sockaddr_in severaddr{ 0 };
severaddr.sin_family = AF_INET;
severaddr.sin_port = htons(8888);
inet_pton(AF_INET, "127.0.0.1", &severaddr.sin_addr);
bind(server, (SOCKADDR*)&severaddr, sizeof(severaddr));
//监听
listen(server, SOMAXCONN);
//会话
sockaddr_in clientaddr{ 0 };
int size = sizeof(clientaddr);
while (1)
{
//获取客户端socket
SOCKET client = accept(server, (SOCKADDR*)&clientaddr, &size);//为了实现我们的多人通信,多个客户端与服务端对话时需要我们去存储多个客户端的socket,实现我们的多人聊天
//所以这里我们通过线程来控制,通过c++中的vector容器来存储我们的socket
client_chat.push_back(client);
CreateThread(NULL, 0X100, Chat_fun, (VOID*)&client, 0, NULL);
printf("客户端%u连接到了服务器\n", client);
}
return 0;
}
客户端:
#include<WinSock2.h>
#include<Windows.h>
#include<iostream>
#include<WS2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
DWORD WINAPI Chat_fun(
LPVOID lpParameter
)
{
char buff[0x100]{ 0 };
SOCKET client = (SOCKET)lpParameter;
while (recv(client,buff,0x100,0)>0)
{
printf("%s\n", buff);
}
return 0;
}
int main()
{
//初始化网络环境
WSADATA date{ 0 };
WSAStartup(MAKEWORD(2, 2), &date);//WSAStartup 函数通过进程启动 Winsock DLL 的使用
//创建socket
SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//绑定socket的端口号IP地址
sockaddr_in severaddr{ 0 };
severaddr.sin_family = AF_INET;
severaddr.sin_port = htons(8888);
inet_pton(AF_INET, "127.0.0.1", &severaddr.sin_addr);
int result = connect(client, (SOCKADDR*)&severaddr, sizeof(severaddr));
if (result)
{
printf("连接失败");
return 0;
}
HANDLE hthread = CreateThread(NULL, 0X100, Chat_fun, (VOID*)&client, 0, NULL);
char buff[0x100]{ 0 };
while (scanf_s("%s",buff,0x100)&&strcmp(buff,"exit"))
{
send(client, buff, strlen(buff) + 1, 0);
}
closesocket(client);
CloseHandle(hthread);
return 0;
}
- 这样的情况对于我们的多人聊天是已经完成了,但是每有一个客户端进行多人聊天时,我们就需要进行线程的开辟,那么假如有成千上万的客户端进行通讯(比如qq,wechat),那我们申请的内存将会是巨大的。
所以面对于这样的一种情况,我们需要做的就是通过IOCP (input/output completion port),通过cup能够承受的最合理的线程进行发配线程,通过队列的形式,假如有聊天的通信就步入队列,让IOCP来分配线程进行聊天
最合理线程数=cup内核数量*2
优化服务器:
#include<WinSock2.h>
#include<Windows.h>
#include<iostream>
#include<WS2tcpip.h>
#include<vector>
typedef struct _my_overlapped
{
WSABUF buff;
OVERLAPPED overlapped;
}MT_OVERLAPPED, * LPMY_OVERAPPED;
using std::vector;
vector<SOCKET> client_chat;
#pragma comment(lib,"ws2_32.lib")
DWORD WINAPI Chat_fun(
LPVOID lpParameter
)
{
BOOL result = FALSE;
HANDLE hComPort = (HANDLE)lpParameter;
DWORD num_byte_Tranf;
ULONG_PTR ComPortKey;
LPMY_OVERAPPED LP_Over_Lapped;
DWORD flag;
while (true)
{
result = GetQueuedCompletionStatus(hComPort, &num_byte_Tranf, &ComPortKey, (LPOVERLAPPED*)&LP_Over_Lapped, INFINITE);
if (result && num_byte_Tranf > 0)
{
for (int i = 0; i < client_chat.size(); i++)
{
if (client_chat[i] != ComPortKey)
{
send(client_chat[i], LP_Over_Lapped->buff.buf, LP_Over_Lapped->buff.len, 0);
}
}
//清空并重新初始化overlapped
memset(&LP_Over_Lapped->overlapped, 0, sizeof(OVERLAPPED));
memset(LP_Over_Lapped->buff.buf, 0, 0x100);
WSARecv(ComPortKey, &LP_Over_Lapped->buff, num_byte_Tranf, &flag, 0, (LPWSAOVERLAPPED)LP_Over_Lapped, NULL);
}
else
{
for (int i = 0; i < client_chat.size(); i++)
if (client_chat[i] == ComPortKey)
{
closesocket(ComPortKey);
client_chat.erase(client_chat.begin() + i);
printf("客户端%u断开了连接\n", ComPortKey);
}
}
}
return 0;
}
int main()
{
//创建IOCP对象
HANDLE hCompletPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
//获取内核数量
SYSTEM_INFO sys_info{ 0 };
GetNativeSystemInfo(&sys_info);
for (int i = 0; i < sys_info.dwNumberOfProcessors * 2; i++)
{
CreateThread(NULL, NULL, Chat_fun, hCompletPort, NULL, NULL);
}
//初始化网络环境
WSADATA date{ 0 };
WSAStartup(MAKEWORD(2, 2), &date);//WSAStartup 函数通过进程启动 Winsock DLL 的使用
//创建socket
SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//绑定socket的端口号IP地址
sockaddr_in severaddr{ 0 };
severaddr.sin_family = AF_INET;
severaddr.sin_port = htons(8888);
inet_pton(AF_INET, "127.0.0.1", &severaddr.sin_addr);
bind(server, (SOCKADDR*)&severaddr, sizeof(severaddr));
//监听
listen(server, SOMAXCONN);
//会话
sockaddr_in clientaddr{ 0 };
int size = sizeof(clientaddr);
while (1)
{
//获取客户端socket
SOCKET client = accept(server, (SOCKADDR*)&clientaddr, &size);//为了实现我们的多人通信,多个客户端与服务端对话时需要我们去存储多个客户端的socket,实现我们的多人聊天
//所以这里我们通过线程来控制,通过c++中的vector容器来存储我们的socket
client_chat.push_back(client);
//将socket关联到IOCP
CreateIoCompletionPort((HANDLE)client, hCompletPort, client, 0);//创建输入/输出 (I/O) 完成端口,并将其与指定的文件句柄相关联,或者创建尚未与文件句柄关联的 I/O 完成端口,以便在以后进行关联。
LPMY_OVERAPPED LP_Over_Lapped = new MT_OVERLAPPED;
LP_Over_Lapped->buff.buf = new char[0x100];
LP_Over_Lapped->buff.len = 0x100;
printf("客户端%u连接到了服务器\n", client);
}
return 0;
}

浙公网安备 33010602011771号