草庐IT

c - 套接字阻塞 :( How do i get out?

coder 2024-06-19 原文

这是我从 microsoft 中获取的服务器代码.下面是我的 main,它需要运行 void important_code(bool);。在 linux 和 windows 上使用管道和套接字时,我总是遇到这个问题。

我如何退出 select()我什么时候想退出我的应用程序?假设 important_code 总是在套接字代码之后的同一个线程上执行。我该怎么做?

我知道这是 windows 代码,但我在 linux 下也遇到了这个问题

额外的测试代码:如果您在我的主函数中注释掉 main2() 并取消注释循环,您可以使用 ctrl+c 干净地退出。使用套接字代码,阻塞 select 阻止我这样做。我该如何解决这个问题?

#pragma comment(lib, "Ws2_32.lib")
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>

#define DEFAULT_FAMILY  AF_UNSPEC
#define DEFAULT_SOCKTYPE SOCK_STREAM
#define DEFAULT_PORT  "1234"
#define BUFFER_SIZE   23    // length of "WinCE Echo Test Packet"

void Print(TCHAR *pFormat, ...)
{
    va_list ArgList;
    TCHAR Buffer[256];
    va_start (ArgList, pFormat);
    (void)StringCchPrintf(Buffer, 256, pFormat, ArgList);

#ifndef UNDER_CE
    _putts(Buffer);
#else
    printf("%s",Buffer);
#endif

    va_end(ArgList);
}

int main2 ()
{
    SOCKET sock, SockServ[FD_SETSIZE];
    int nFamily = DEFAULT_FAMILY;
    int nSockType = DEFAULT_SOCKTYPE;
    char *szPort = DEFAULT_PORT;
    SOCKADDR_STORAGE ssRemoteAddr;
    int i, nNumSocks, cbRemoteAddrSize, cbXfer, cbTotalRecvd;
    WSADATA wsaData;
    ADDRINFO Hints, *AddrInfo = NULL, *AI;
    fd_set fdSockSet;
    char pBuf[BUFFER_SIZE];
    char szRemoteAddrString[128];

    if(WSAStartup(MAKEWORD(2,2), &wsaData))
    {
        // WSAStartup failed
        return 1;
    }

    sock = INVALID_SOCKET;

    for(i = 0; i < FD_SETSIZE; i++)
        SockServ[i] = INVALID_SOCKET;

    //
    // Get a list of available addresses to serve on
    //

    memset(&Hints, 0, sizeof(Hints));
    Hints.ai_family = nFamily;
    Hints.ai_socktype = nSockType;
    Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;

    if(getaddrinfo(NULL, szPort, &Hints, &AddrInfo))
    {
        Print(TEXT("ERROR: getaddrinfo failed with error %d\r\n"), WSAGetLastError());
        goto Cleanup;
    }

    //
    // Create a list of serving sockets, one for each address
    //

    i = 0;
    for(AI = AddrInfo; AI != NULL; AI = AI->ai_next) 
    {
        if (i == FD_SETSIZE) 
        {
            // getaddrinfo returned more addresses than we could use
            break;
        }

        if((AI->ai_family == PF_INET) || (AI->ai_family == PF_INET6)) // only want PF_INET or PF_INET6
        {
            SockServ[i] = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol);
            if (SockServ[i] != INVALID_SOCKET)
            {
                if (bind(SockServ[i], AI->ai_addr, AI->ai_addrlen) == SOCKET_ERROR)
                    closesocket(SockServ[i]);
                else 
                {
                    if(nSockType == SOCK_STREAM)
                    {
                        if (listen(SockServ[i], 5) == SOCKET_ERROR)
                        {
                            closesocket(SockServ[i]);
                            continue;
                        }
                    }

                    Print( 
                        TEXT("Socket 0x%08x ready for connection with %hs family, %hs type, on port %hs\r\n"), 
                        SockServ[i], 
                        (AI->ai_family == AF_INET) ? "AF_INET" : ((AI->ai_family == AF_INET6) ? "AF_INET6" : "UNKNOWN"),
                        (AI->ai_socktype == SOCK_STREAM) ? "TCP" : ((AI->ai_socktype == SOCK_DGRAM) ? "UDP" : "UNKNOWN"),
                        szPort);
                    i++;
                }
            }
        }
    }

    freeaddrinfo(AddrInfo);

    if (i == 0) 
    {
        Print(TEXT("ERROR: Unable to serve on any address. Error = %d\r\n"), WSAGetLastError());
        goto Cleanup;
    }

    //
    // Wait for incomming data/connections
    //

    nNumSocks = i;

    FD_ZERO(&fdSockSet);

    for (i = 0; i < nNumSocks; i++)    // want to check all available sockets
        FD_SET(SockServ[i], &fdSockSet);

    if (select(nNumSocks, &fdSockSet, 0, 0, NULL) == SOCKET_ERROR)
    {
        Print(TEXT("ERROR: select() failed with error = %d\r\n"), WSAGetLastError());
        goto Cleanup;
    }

    for (i = 0; i < nNumSocks; i++)    // check which socket is ready to process
    {
        if (FD_ISSET(SockServ[i], &fdSockSet))    // proceed for connected socket
        {
            FD_CLR(SockServ[i], &fdSockSet);
            if(nSockType == SOCK_STREAM)
            {
                cbRemoteAddrSize = sizeof(ssRemoteAddr);
                sock = accept(SockServ[i], (SOCKADDR*)&ssRemoteAddr, &cbRemoteAddrSize);
                if(sock == INVALID_SOCKET) 
                {
                    Print(TEXT("ERROR: accept() failed with error = %d\r\n"), WSAGetLastError());
                    goto Cleanup;
                }

                Print(TEXT("Accepted TCP connection from socket 0x%08x\r\n"), sock);
            }
            else
            {
                sock = SockServ[i];
                Print(TEXT("UDP data available on socket 0x%08x\r\n"), sock);
            }
            break;        // Only need one socket
        }
    }

    //
    // Receive data from a client
    //

    cbTotalRecvd = 0;
    do
    {
        cbRemoteAddrSize = sizeof(ssRemoteAddr);
        cbXfer = recvfrom(sock, pBuf + cbTotalRecvd, sizeof(pBuf) - cbTotalRecvd, 0,
            (SOCKADDR *)&ssRemoteAddr, &cbRemoteAddrSize);
        cbTotalRecvd += cbXfer;
    } while(cbXfer > 0 && cbTotalRecvd < sizeof(pBuf));

    if(cbXfer == SOCKET_ERROR)
    {
        Print(TEXT("ERROR: Couldn't receive the data! Error = %d\r\n"), WSAGetLastError());
        goto Cleanup;
    }
    else if(cbXfer == 0)
    {
        Print(TEXT("ERROR: Didn't get all the expected data from the client!\r\n"));
        goto Cleanup;
    }

    if(nSockType == SOCK_STREAM)
    {
        cbRemoteAddrSize = sizeof(ssRemoteAddr);
        getpeername(sock, (SOCKADDR *)&ssRemoteAddr, &cbRemoteAddrSize);
    }

    if (getnameinfo((SOCKADDR *)&ssRemoteAddr, cbRemoteAddrSize,
        szRemoteAddrString, sizeof(szRemoteAddrString), NULL, 0, NI_NUMERICHOST) != 0)
        strcpy(szRemoteAddrString, "");

    Print(TEXT("SUCCESS - Received %d bytes from client %hs\r\n"), cbTotalRecvd, szRemoteAddrString);

    //
    // Echo the data back to the client
    //

    cbXfer = 0;
    cbXfer = sendto(sock, pBuf, cbTotalRecvd, 0, (SOCKADDR *)&ssRemoteAddr, cbRemoteAddrSize);

    if(cbXfer != cbTotalRecvd)
        Print(TEXT("ERROR: Couldn't send the data! error = %d\r\n"), WSAGetLastError());
    else
        Print(TEXT("SUCCESS - Echo'd %d bytes back to the client\r\n"), cbXfer);

Cleanup:

    for(i = 0; i < nNumSocks && SockServ[i] != INVALID_SOCKET; i++)
        closesocket(SockServ[i]);

    if(sock != INVALID_SOCKET)
    {
        shutdown(sock, SD_BOTH);
        closesocket(sock);
    }

    WSACleanup();

    return 0;
}



#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

volatile bool terminate_app=false;
void terminate (int param)
{
    printf("Terminating program...\n");
    terminate_app=true;
}

void important_code(bool v)
{
    printf("Important code here %d\n", v);
}

int main ()
{
    try{
        void (*prev_fn)(int);

        prev_fn = signal (SIGINT,terminate);

        main2();
        //while(terminate_app==false)
        {
        }
    }
    catch(...){
        important_code(1);
    }
    important_code(0);
    return 0;
}

最佳答案

在 POSIX 上 select() 将在超时时返回,或者当其中一个描述符准备就绪时返回,或者如果它被一个信号。

因此,您可以使用 EINTR 行为。只需使用 sigaction() 函数安装一个信号处理程序,而无需 SA_RESTART(重新启动被信号中断的系统调用)标志。 (signal() 的行为因系统而异,在某些系统上,它可以通过 #defines 进行更改)。

或者,您可以使用自管道技巧:写入管道以发出您想要退出的信号。如果您的 select() 选择了该管道的读取描述符,它将返回。

关于c - 套接字阻塞 :( How do i get out?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9491633/

有关c - 套接字阻塞 :( How do i get out?的更多相关文章

  1. 网络编程套接字 - 2

    网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识

  2. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

    s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

  3. ruby-on-rails - Ruby 的 'open_uri' 是否在读取或失败后可靠地关闭套接字? - 2

    一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我

  4. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

  5. ruby - 使用 ruby​​ 进行套接字编程是个好主意吗? - 2

    我选择的语言是Ruby,但因为Twitter,我知道Ruby不能处理很多请求。将它用于套接字开发是个好主意吗?或者我应该像Twitter开发人员那样使用像erlang或haskell或scala这样的函数式语言吗? 最佳答案 我工作的公司使用Ruby作为我们的网站。到目前为止,我们已经处理了超过34,000,000,000次点击。我们每天处理大约10,000,000次点击没有问题。每天的点击量峰值已超过40,000,000次。可扩展性取决于很多因素。例如,与读取相比,我们的数据库执行的写入比例高得不成比例。虽然大多数网站执行大约90

  6. ruby - 重新连接 tcpsocket(或如何检测已关闭的套接字) - 2

    我有一个连接到服务器的ruby​​tcpsocket客户端。在发送数据之前如何检查套接字是否已连接?我是否尝试“拯救”断开连接的tcpsocket,重新连接然后重新发送?如果是这样,有没有人有一个简单的代码示例,因为我不知道从哪里开始:(我很自豪我设法在rails中获得了一个持久连接的客户端tcpsocket。然后服务器决定杀死客户端,一切都崩溃了;)编辑我已经使用此代码解决了一些问题-如果未连接,它将尝试重新连接,但如果服务器已关闭则不会处理这种情况(它将继续重试)。这是正确方法的开始吗?谢谢defself.write(data)begin@@my_connection.write(

  7. ruby-on-rails - Rails 是否支持监听 UDP 套接字的简洁方式? - 2

    在Rails中,什么是集成更新模型某些元素的UDP监听过程的最佳方式(特别是它将向其中一个表添加行)。简单的答案似乎是在同一个进程中使用UDP套接字对象启动一个线程,但我什至不清楚我应该在哪里做适合Rails方式的事情。有没有一种巧妙的方法来开始收听UDP?具体来说,我希望能够编写一个UDPController并在每个数据报消息上调用一个特定的方法。理想情况下,我希望避免在UDP上使用HTTP(因为它会浪费一些在这种情况下非常宝贵的空间),但我完全控制消息格式,因此我可以为Rails提供它需要的任何信息。 最佳答案 Rails是一个

  8. ruby - IO::EAGAINWaitReadable:资源暂时不可用 - 读取会阻塞 - 2

    当我尝试使用“套接字”库中的方法“read_nonblock”时出现以下错误IO::EAGAINWaitReadable:Resourcetemporarilyunavailable-readwouldblock但是当我通过终端上的IRB尝试时它工作正常如何让它读取缓冲区? 最佳答案 IgetthefollowingerrorwhenItrytousethemethod"read_nonblock"fromthe"socket"library当缓冲区中的数据未准备好时,这是预期的行为。由于异常IO::EAGAINWaitReadab

  9. ruby - 如何在 Ruby 中创建双向 SSL 套接字 - 2

    我正在构建一个连接到服务器并等待数据的客户端Ruby库,但也允许用户通过调用方法发送数据。我使用的机制是有一个初始化套接字对的类,如下所示:definitialize@pipe_r,@pipe_w=Socket.pair(:UNIX,:STREAM,0)end我允许开发人员调用以将数据发送到服务器的方法如下所示:defsend(data)@pipe_w.write(data)@pipe_w.flushend然后我在一个单独的线程中有一个循环,我从连接到服务器的socket和@pipe_r中选择:defsocket_loopThread.newdosocket=TCPSocket.new

  10. ruby - ENOENT 在 Ruby 中创建 UNIX 套接字时 - 2

    我正在尝试使用Ruby创建套接字require"socket"w=UNIXSocket.new("socket")我不断遇到Nosuchfileordirectory-socket(Errno::ENOENT)这对我来说完全是倒退,因为new()应该创建那个丢失的文件。我错过了什么? 最佳答案 这太老了。请不要再尝试逐字使用它。http://blog.antarestrader.com/posts/153#!/rubyfile='path/to/my/socket'File.unlinkifFile.exists(file)&&Fi

随机推荐