Windows平台基于多进程的echo服务器简单实现

本文介绍了一个基于Windows平台的多进程Echo服务器实现方法。通过创建多个子进程来处理客户端连接请求,每个子进程负责与一个客户端进行通信。文章详细展示了使用WinSock进行网络编程的具体步骤,并提供了完整的代码示例。

这里的Echo服务器就是说客户端发什么,服务器端立刻返回什么。一种常见的实现是基于多线程的,在linux上还很容易就用fork实现一个多进程的服务器。

下面演示一下在Windows平台如何用多进程来实现一个echo服务器。


/*
 *  @file  : TestEchoServerMultiProcess.cpp
 *  @author: Shilyx
 *  @date  : 2014-04-23 08:43:27.206
 *  @note  : Generated by SlxTemplates, 多进程echo服务器演示
 */

#include <WinSock2.h>
#include <Windows.h>
#include <Shlwapi.h>
#pragma warning(disable: 4786)
#include <iostream>

#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Shlwapi.lib")

using namespace std;

// 初始化WinSock,未检查返回值
void InitWinSock()
{
    WSADATA wd;

    WSAStartup(MAKEWORD(2, 2), &wd);
}

void Serve(USHORT port)
{
    InitWinSock();

    SOCKET sock_base = INVALID_SOCKET;

    do
    {
        sock_base = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

        if (sock_base == INVALID_SOCKET)
        {
            cerr<<"socket error "<<WSAGetLastError()<<endl;
            break;
        }

        sockaddr_in sin;

        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = INADDR_ANY;
        sin.sin_port = htons(port);

        if (SOCKET_ERROR == bind(sock_base, (sockaddr *)&sin, sizeof(sin)))
        {
            cerr<<"bind error "<<WSAGetLastError()<<endl;
            break;
        }

        if (SOCKET_ERROR == listen(sock_base, 100))
        {
            cerr<<"listen error "<<WSAGetLastError()<<endl;
            break;
        }

        HANDLE hProcess = NULL;
        DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &hProcess, 0, TRUE, DUPLICATE_SAME_ACCESS);

        if (NULL == hProcess)
        {
            cerr<<"DuplicateHandle error "<<GetLastError()<<endl;
            break;
        }

        TCHAR szSelfPath[MAX_PATH];

        GetModuleFileName(GetModuleHandle(NULL), szSelfPath, RTL_NUMBER_OF(szSelfPath));
        PathQuoteSpaces(szSelfPath);

        while (true)
        {
            int len = sizeof(sin);
            SOCKET sock = accept(sock_base, (sockaddr *)&sin, &len);

            if (sock == INVALID_SOCKET)
            {
                cerr<<"accept error "<<WSAGetLastError()<<endl;
                break;
            }
            else
            {
                TCHAR szCommand[MAX_PATH * 2];
                STARTUPINFO si = {sizeof(si)};
                PROCESS_INFORMATION pi;

                si.dwFlags = STARTF_USESHOWWINDOW;
                si.wShowWindow = SW_SHOW;

                wnsprintf(szCommand, RTL_NUMBER_OF(szCommand), TEXT("%s %u %u"), szSelfPath, sock, hProcess);

                if (CreateProcess(NULL, szCommand, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
                {
                    CloseHandle(pi.hProcess);
                    CloseHandle(pi.hThread);
                }
                else
                {
                    cerr<<"CreateProcess error "<<GetLastError()<<endl;
                }

                closesocket(sock);
            }
        }

    } while (false);

    if (sock_base != INVALID_SOCKET)
    {
        closesocket(sock_base);
    }
}

DWORD CALLBACK WorkProc(LPVOID lpParam)
{
    SOCKET sock = (SOCKET)lpParam;

    while (TRUE)
    {
        char szBuffer[4096];
        int len = recv(sock, szBuffer, sizeof(szBuffer), 0);

        if (len <= 0)
        {
            break;
        }

        if (send(sock, szBuffer, len, 0) <= 0)
        {
            break;
        }
    }

    closesocket(sock);

    return 0;
}

void Work(SOCKET sock, HANDLE hParentProcess)
{
    InitWinSock();

    HANDLE hObjects[] = {hParentProcess, CreateThread(NULL, 0, WorkProc, (LPVOID)sock, 0, NULL)};

    WaitForMultipleObjects(RTL_NUMBER_OF(hObjects), hObjects, FALSE, INFINITE);

    CloseHandle(hObjects[0]);
    CloseHandle(hObjects[1]);
}

int main(int argc, char *argv[])
{
    // 加端口参数启动为父进程
    // 加套接字句柄参数和进程句柄参数为子进程
    // 不加参数显示用法

    if (argc == 2)
    {
        int port = StrToIntA(argv[1]);

        if (port < 0 || port > 65535)
        {
            cerr<<"端口错误:"<<port<<endl;
            return 0;
        }

        // 在端口port处启动echo服务器
        Serve((USHORT)port);
    }
    else if (argc == 3)
    {
        SOCKET sock = StrToIntA(argv[1]);
        HANDLE hParentProcess = (HANDLE)StrToIntA(argv[2]);

        // 针对具体tcp连接套接字和父进程句柄开始echo工作
        Work(sock, hParentProcess);
    }
    else
    {
        cout<<"加端口参数启动为父进程"<<endl
            <<"加套接字句柄参数和进程句柄参数为子进程"<<endl
            <<"不加参数显示用法"<<endl;
    }

    return 0;
}




                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值