[英]Winsock local client-server benchmarking
我打算評估這種簡單的客戶端-服務器程序的性能,該程序以測試客戶端發出固定數量的請求的方式進行設置;例如, 10000,然后查看服務器處理這些文件要花多長時間,然后再並行處理多個客戶端,因為它與線程一起運行。 現在我想知道如何編程嗎? (對不起,剛開始是Winsock)。 我還想知道這是否是線程的正確實現,如果不能,則可以改進什么,為什么。 提前致謝
測試服務器代碼;
服務器:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#pragma comment(lib,"ws2_32.lib") //header file
#include <WinSock2.h>
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
SOCKET Connections[100];
int ConnectionCounter = 0;
void ClientHandlerThread(int index) //index = the index in the SOCKET Connections array
{
char buffer[256]; //Buffer to receive and send out messages from/to the clients
while (true)
{
recv(Connections[index], buffer, sizeof(buffer), NULL); //get message from client
for (int i = 0; i < ConnectionCounter; i++) //For each client connection
{
if (i == index) //Don't send the chat message to the same user who sent it
continue; //Skip user
send(Connections[i], buffer, sizeof(buffer), NULL);//send the chat message to this client
}
}
}
int main()
{
std::cout << "\n\n\n\n\n Server sucessfully turned on, awaiting for clients...\n\n\n\n\n";
//Winsock Startup
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0) //initialise winsock library, if WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
{
MessageBoxA(NULL, "WinSock startup failed", "Error", MB_OK | MB_ICONERROR);
return 0;
}
SOCKADDR_IN addr; //Address that we will bind our listening socket to
int addrlen = sizeof(addr); //length of the address (required for accept call)
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //Broadcast locally, using inet_address funtion that converts to correct long format.
addr.sin_port = htons(1111); //Port
addr.sin_family = AF_INET; //IPv4 Socket
SOCKET sListen = socket(AF_INET, SOCK_STREAM, NULL); //Create socket to listen for new connections
bind(sListen, (SOCKADDR*)&addr, sizeof(addr)); //Bind the address to the socket
listen(sListen, SOMAXCONN); //Places sListen socket in a state in which it is listening for an incoming connection. Note:SOMAXCONN = Socket Oustanding Max Connections
SOCKET newConnection; //Socket to hold the client's connection
int ConnectionCounter = 0; //# of client connections
for (int i = 0; i < 100; i++)
{
newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen); //Accept a new connection
if (newConnection == 0) //If accepting the client connection failed
{
std::cout << "Failed to accept the client's connection." << std::endl;
}
else //If client connection properly accepted
{
std::cout << "\n\n\nClient Connected!\n\n" << std::endl;
/* char MOTD[256] = "Welcome! This is the Message of the Day."; //Create buffer with message of the day
send(newConnection, MOTD, sizeof(MOTD), NULL); //Send MOTD buffer */
Connections[i] = newConnection; //Set socket in array to be the newest connection before creating the thread to handle this client's socket.
ConnectionCounter += 1; //Incremenent total # of clients that have connected
cout << "\nConnected Clients: ";
cout << ConnectionCounter;
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientHandlerThread, (LPVOID)(i), NULL, NULL); //Create Thread to handle this client. The index in the socket array for this thread is the value (i).
}
}
system("pause");
return 0;
}
客戶:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#pragma comment(lib,"ws2_32.lib") //Required for WinSock
#include <WinSock2.h> //For win sockets
#include <string> //For std::string
#include <iostream> //For std::cout, std::endl, std::cin.getline
SOCKET Connection;//This client's connection to the server
void ClientThread()
{
char buffer[256]; //Create buffer to hold messages up to 256 characters
while (true)
{
recv(Connection, buffer, sizeof(buffer), NULL); //receive buffer
std::cout << buffer << std::endl; //print out buffer
}
}
int main()
{
//Winsock Startup
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0)
{
MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);
return 0;
}
SOCKADDR_IN addr; //Address to be binded to our Connection socket
int sizeofaddr = sizeof(addr); //Need sizeofaddr for the connect function
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //Address = localhost (this pc)
addr.sin_port = htons(1111); //Port = 1111
addr.sin_family = AF_INET; //IPv4 Socket
Connection = socket(AF_INET, SOCK_STREAM, NULL); //Set Connection socket
if (connect(Connection, (SOCKADDR*)&addr, sizeofaddr) != 0) //If we are unable to connect...
{
MessageBoxA(NULL, "Failed to Connect", "Error", MB_OK | MB_ICONERROR);
return 0; //Failed to Connect
}
std::cout << "Connected!" << std::endl;
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientThread, NULL, NULL, NULL); //Create the client thread that will receive any data that the server sends.
char buffer[256]; //256 char buffer to send message
while (true)
{
std::cin.getline(buffer, sizeof(buffer)); //Get line if user presses enter and fill the buffer
send(Connection, buffer, sizeof(buffer), NULL); //Send buffer
Sleep(10);
}
return 0;
}
正如@JerryCoffin所說,使用“每個客戶端線程”模型會使線程之間的上下文切換過多,從而給服務器帶來負擔。 Nginx Web服務器等現代服務器使用異步非阻塞模型來實現可伸縮性。 我最近開發了這樣的架構。 為了更熟悉此模型,我為您提供了一些有用的鏈接。
從以下內容開始,以更熟悉該概念:
您需要了解re-actor和pro-actor設計模式。 您可以使用select()或類似的工具來實現它們。
在boost,POCO和ACE之類的庫中也有一些不錯的實現。 就個人而言,我建議您看一下boost asio庫。 您可以在此處找到完整的文檔,教程和示例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.