C++ - 每个 Tcp 连接的进程

Posted

技术标签:

【中文标题】C++ - 每个 Tcp 连接的进程【英文标题】:C++ - Process per Tcp connection 【发布时间】:2016-07-25 13:44:37 【问题描述】:

我需要创建进程并将连接的套接字传递给新创建的进程,对套接字的进一步操作将在新进程中发生。我使用了以下代码。一切正常,但是当我在工作完成后尝试关闭子进程时,它会在该行引发访问冲突,

return InterlockedCompareExchangePointer(dest, exch, cmp);

在文件“win_iocp_socket_service_base.ipp”中,该文件位于路径“boost\asio\detail\impl”中

下面是我的代码。

#include <iostream>
#include <tchar.h>
#define BOOST_ASIO_DISABLE_IOCP 1
#include <boost/thread/thread.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time.hpp>

#ifdef _WIN32
#include "Windows.h"
#endif
#include <string>

using namespace boost::asio::ip;
using namespace std;

int main(int argc, char* argv[])
    cout << "Current Process Id...." << GetCurrentProcessId() << endl;
    cout << "Argument count..." << argc << endl;
    if (3 == argc)
        boost::this_thread::sleep(boost::posix_time::seconds(15));
        ostringstream ss;
        ss << argv[2];
        if (ss.str() == "CHILD")
            cout << "Message To child...." << ss.str() << endl;
            try
            
                SOCKET Sock;
                if (2 < argc)
                    Sock = atoi(argv[1]);   // use Sock
                
                boost::asio::io_service io_service2;
                tcp::socket s(io_service2);
                s.assign(tcp::v4(), Sock); 
                s.send(boost::asio::buffer("Message to client\r\n"));
                s.close();
                return 0;
            
            catch (exception &e)
            
                cerr << e.what() << endl; //"The parameter is incorrect" exception
            
            return 0;
        
    

    int m_nPort = 12345;
    boost::asio::io_service io_service;
    tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), m_nPort));

    cout << "Waiting for connection..." << endl;

    tcp::socket socket(io_service);
    acceptor.accept(socket);
    cout << "connection accepted" << endl;

#ifdef _WIN32
    WSAPROTOCOL_INFO pi;
    WSADuplicateSocket(socket.native(), GetCurrentProcessId(), &pi);
    SOCKET socketDup = WSASocket(pi.iAddressFamily/*AF_INET*/, pi.iSocketType/*SOCK_STREAM*/,
        pi.iProtocol/*IPPROTO_TCP*/, &pi, 0, 0);
#else
    //linux
    int socketDup = dup(socket.native()); // tested on Linux, works!
#endif

    
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        TCHAR argbuf[256];

        memset(&si, 0, sizeof(si));
        wsprintf(argbuf, _T("Server.exe %d %s"), socketDup, _T("\"CHILD\""));
        if (!CreateProcess(NULL, argbuf, NULL, NULL,
            TRUE, // inherit handles
            0, NULL, NULL, &si, &pi))
            fprintf(stderr, "createprocess failed %d\n", GetLastError());
            return -1;
                
        WaitForSingleObject(pi.hProcess, INFINITE);
    
    socket.close();
    cin.get();

我发现错误是由这个"#define BOOST_ASIO_DISABLE_IOCP 1"引起的

但是没有这个,我不能在这一行复制套接字,s.assign(tcp::v4(), Sock);

我该如何解决这个问题,请帮助我。

【问题讨论】:

抱歉,我将其视为将其传递给线程而不是进程。 WSADuplicateSocket 是正确的方法。当您关闭子进程时,您是否关闭父进程上的套接字? 为什么?这就是 1980 年代套接字的编程方式。这些天你会使用线程。 【参考方案1】:

我将此误解为从“线程”而不是“进程”复制套接字时视力不佳。 WSADuplicateSocket 函数是正确的。但是需要注意的是,底层套接字将保持打开状态,直到该套接字的所有描述符(包括父级)都被释放。 WSADuplicate

直接来自 MSDN:

一个进程可以在一个重复的套接字上调用 closesocket 并且 描述符将被释放。然而,底层的套接字, 将保持打开状态,直到最后剩下的调用 closesocket 描述符。

【讨论】:

如何在创建的子进程中使用这个套接字。 您还需要在父节点上调用 close,参见上面的 MSDN 描述。【参考方案2】:

我终于得到了解决方案。

1.评论该行

#define BOOST_ASIO_DISABLE_IOCP 1

2.将套接字更改为共享指针。 -感谢@Samer Tufail 的共享指针建议

我的工作代码。

#include <iostream>
#include <tchar.h>
#include <boost/thread/thread.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time.hpp>

#ifdef _WIN32
#include "Windows.h"
#endif
#include <string>

using namespace boost::asio::ip;
using namespace std;

int main(int argc, char* argv[])
    cout << "Current Process Id...." << GetCurrentProcessId() << endl;
    cout << "Argument count..." << argc << endl;
    if (3 == argc)
        boost::this_thread::sleep(boost::posix_time::seconds(15));
        ostringstream ss;
        ss << argv[2];
        if (ss.str() == "CHILD")
            cout << "Message To child...." << ss.str() << endl;
            try
            
                SOCKET Sock;
                if (2 < argc)
                    Sock = atoi(argv[1]);   // use Sock
                
                boost::asio::io_service io_service2;
                tcp::socket s(io_service2);
                io_service2.run();
                s.assign(tcp::v4(), Sock); 
                s.send(boost::asio::buffer("Message to client\r\n"));
                s.close();
                return 0;
            
            catch (exception &e)
            
                cerr << e.what() << endl; 
            
            return 0;
        
    

    int m_nPort = 12345;
    boost::asio::io_service io_service;
    tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), m_nPort));

    cout << "Waiting for connection..." << endl;

    boost::shared_ptr<tcp::socket> socket(new tcp::socket(io_service));
    acceptor.accept(*socket);
    cout << "connection accepted" << endl;

#ifdef _WIN32
    WSAPROTOCOL_INFO pi;
    WSADuplicateSocket(socket->native(), GetCurrentProcessId(), &pi);
    SOCKET socketDup = WSASocket(pi.iAddressFamily/*AF_INET*/, pi.iSocketType/*SOCK_STREAM*/,
        pi.iProtocol/*IPPROTO_TCP*/, &pi, 0, 0);
#else
    //linux
    int socketDup = dup(socket.native()); // tested on Linux, works!
#endif

    
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        TCHAR argbuf[256];

        memset(&si, 0, sizeof(si));
        wsprintf(argbuf, _T("Server.exe %d %s"), socketDup, _T("\"CHILD\""));
        if (!CreateProcess(NULL, argbuf, NULL, NULL,
            TRUE, // inherit handles
            0, NULL, NULL, &si, &pi))
            fprintf(stderr, "createprocess failed %d\n", GetLastError());
            return -1;
                
        WaitForSingleObject(pi.hProcess, INFINITE);
    
    cin.get();

【讨论】:

以上是关于C++ - 每个 Tcp 连接的进程的主要内容,如果未能解决你的问题,请参考以下文章

c++ 服务器在客户端终止连接进程后不关闭 TCP 套接字连接

powershell 显示本地或远程系统的当前TCP / IP连接。包括每个连接的进程ID(PID)和进程名称。如果

请问linux怎么增大socket连接上限?

TCP关闭连接 - 不容易

TCP套接字端口复用SO_REUSEADDR

获取活动 udp 连接的目标 IP/端口?