Winsock本地客户端 - 服务器基准测试

时间:2018-04-26 14:28:13

标签: c++ winsock

我想要评估这个简单的客户端 - 服务器程序的性能,以一种测试客户端发出固定数量的请求的方式设置它,比如说; 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;
}

1 个答案:

答案 0 :(得分:0)

正如@JerryCoffin所说,使用线程每个客户端模型会在线程之间进行过多的上下文切换。像Nginx Web服务器这样的现代服务器使用异步非阻塞模型来实现可伸缩性。我最近开发了这样的架构。为了更熟悉这个模型,我为您提供了一些有用的链接。

从以下开始,更加熟悉这个概念:

Inside NGINX: How We Designed for Performance & Scale

您需要了解 re-actor pro-actor 设计模式。您可以使用select()或类似工具来实现它们。

Example: Nonblocking I/O and select()

在boost,POCO和ACE等库中也有一些不错的实现。就个人而言,我建议你看一下boost asio库。您可以在此处找到完整的文档,教程和示例。

Boost.Asio