初识Socket编程——基于流式套接字的多线程并发服务器回射程序设计

实验三、基于流式套接字的多线程并发服务器回射程序设计

0x00 实验内容

将 实验二 中的服务器改为并发服务器。

0x01 实现过程

实现方法

这个和 实验二 中的代码只差一部分——只需要让服务器开一个线程单独为当前客户服务即可。我这里是使用 pthread.h 来实现创建线程的。

公共函数中修改部分

// comm.h
// 在实验二的基础上添加如下内容
#include 
void *asyncTcpEchoServer(LPVOID pParam)
{
    int sock_res;
    char recv_data[MAXLINE];

    // 将输入参数转换成连接套接字
    SOCKET sock_conn = *((SOCKET *)pParam);
    do
    {
        memset(recv_data, 0, MAXLINE);

        // 接收数据
        sock_res = recv(sock_conn, recv_data, MAXLINE, 0);
        if (sock_res > 0)
        {
            cout << "The Data Received From Client Is:" << recv_data << endl;

            // 回射接收的数据
            sock_res = send(sock_conn, recv_data, sock_res, 0);
            if (sock_res == SOCKET_ERROR)
            {
                cout << WSAGetLastError() << "Send Error!" << endl;
                sock_res = -1;
            }
            else
            {
                cout << "The Data Sent From Server Is:" << recv_data << endl;
            }
        }
        else
        {
            if (sock_res == 0)
            {
                cout << "Client is closed!" << endl;
            }
            else
            {
                cout << WSAGetLastError() << "Recv Error!" << endl;
                sock_res = -1;
            }
            break;
        }
    } while (sock_res > 0);
    if (sock_res == -1)
    {
        cout << "Disconnected or Sth. Error" << endl;
    }
    return nullptr;
}

Server 端

// server.cpp
#include "comm.h"

int main(int argc, char *argv[])
{
    int res = -1;
    SOCKET sock_conn;
    SOCKET sock_listen;
    pthread_t pThread;
    char buff[MAXLINE]; //缓冲区

    // 启动
    res = startUp();
    if (res == -1) return -1;

    //监听
    sock_listen = tcpServer(SEVER_PORT);
    if (sock_listen == -1) return -1;

    cout << "Server Start!" << endl;

    while (true)
    {
        //接受客户端连接请求,返回连接套接字sock_conn
        sock_conn = accept(sock_listen, nullptr, nullptr);

        if (sock_conn != INVALID_SOCKET)
        {
            cout << "Conn Success!" << endl;
            // 创建线程
            pthread_create(&pThread, nullptr, asyncTcpEchoServer, &sock_conn);
        }
        else
        {
            cout << WSAGetLastError() << "Accept Error!" << endl;
            closeConn(sock_listen);
            return -1;
        }
    }

    // 关闭连接
    closeConn(sock_listen);
    return 0;
}

Client 端无需改动

附:某些情况下可以考虑使用 select 来实现并发,用select在一些场景下可以有效解决线程膨胀问题。

你可能感兴趣的:(计算机网络,Socket编程)