首页 > 解决方案 > 等待接受方法 30 秒后退出服务器

问题描述

我有代码:

int client_fd = accept(fd, (struct sockaddr*) &client_address, &len);

服务器在这一行等待。如果 30 秒内没有传入连接请求,我想退出服务器。如何做到这一点?

下面的代码基本上等待来自客户端的传入请求并进行一些处理。但其中大部分可能对我们正在讨论的超时事情毫无用处。可能只有 accept 方法上面的部分很重要。

为清楚起见,在此处粘贴完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>   
#include <time.h>
#include <sys/time.h>

#include <iostream> 
#include <map>
using namespace std; 

void Trans( int n );
char* getEpochTime(char* epochTime);

int main(int argc, char *argv[]) {
    char epochTime[20];
    char startEpochTime[20];
    strcpy(startEpochTime, getEpochTime(startEpochTime));
    bool epochFlag = false;
    char endEpochTime[20];
    strcpy(endEpochTime, getEpochTime(endEpochTime));
    int port = atoi(argv[1]);
    int transactionNumber=0;
    std::map<std::string, int> summaryMap; 
    int fd = socket(AF_INET, // an Internet socket
                    SOCK_STREAM, // reliable stream-like socket
                    0); // OS determine the protocol (TCP)

    if (fd < 0)
        return 1; // something went wrong

    struct sockaddr_in serv_addr; 

    fd_set  readfds;

    FD_ZERO(&readfds);
    FD_SET(fd, &readfds);

    struct timeval timeout;
    timeout.tv_sec = 10;
    timeout.tv_usec = 0;

    // setup server address
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(port); // port

    if (bind(fd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) // bind socket to the server address
        return 1;
    
    if (listen(fd, 1) < 0) // wait for clients, only 1 is allowed.
        return 1;
    printf("Using port %d\n",port);

    while(1) {

        struct sockaddr_in client_address; // client address
        socklen_t clientLen;

        clientLen = sizeof(client_address); 
        int client_fd;
        if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0)
        {
            client_fd = accept(fd, (struct sockaddr*) &client_address, &clientLen);  // accept connection
        }
        else {
            break;
        }

        if (client_fd < 0) // bad connection
            continue; // discard

        char buffer[1024];
        int count = 0;
        count = read(client_fd, buffer, sizeof(buffer));
        char hostname[30];
        if(count > 0) {
            transactionNumber++;
            buffer[count] = '\0';
            char *pt;
            pt = strtok (buffer,",");
            char message[10];
            strcpy(message,pt);
            printf("%s\n", message);
            pt = strtok (NULL,",");
            char epoch[20];
            strcpy(epoch,pt);
            pt = strtok (NULL,",");
            strcpy(hostname,pt);
            summaryMap[hostname]++; 
            if(!epochFlag) {
                strcpy(startEpochTime,epoch);
                epochFlag=true;
            }
            printf("%s: # %d (%s) from %s\n",epoch,transactionNumber, message, hostname);
            int transactionExecutionLength;
            sscanf(message+1,"%d", &transactionExecutionLength);
            Trans(transactionExecutionLength);
        }
        char clientMessage[50];
        char _epochTime[50];
        strcpy(_epochTime, getEpochTime(_epochTime));
        sprintf(clientMessage,"%d,%s",transactionNumber,_epochTime);
        write(client_fd, clientMessage, sizeof(clientMessage)); 
        printf("%s: # %d (Done) from %s\n",_epochTime,transactionNumber, hostname);
        stpcpy(endEpochTime,_epochTime);
    }
    map<string, int>::iterator it;
    for ( it = summaryMap.begin(); it != summaryMap.end(); it++ )
    {
        std::cout << it->first  // string (key)
                  << ':'
                  << it->second   // string's value 
                  << std::endl ;
    }

    double startTime = std::stod(startEpochTime);
    double endTime = std::stod(endEpochTime);
    double TotalTime = endTime - startTime;
    return 0;
} 

char* getEpochTime(char* epochTime){
    struct timeval current_time;
    gettimeofday(&current_time, NULL);
    char epochTimeMilli[100];
    char partialSeconds[10];
    sprintf(epochTimeMilli, "%ld", current_time.tv_sec); 
    sprintf(partialSeconds, ".%d", (int)(current_time.tv_usec/10000));    
    strcat(epochTimeMilli, partialSeconds);
    epochTime = epochTimeMilli;
    return epochTime;
}

void Trans( int n ) {
    int TransSave = 0;
    long i, j;

    // Use CPU cycles 
    j = 0;
    for( i = 0; i < n * 100000; i++ ) {
        j += i ^ (i+1) % (i+n);
    }
    TransSave += j;
    TransSave &= 0xff;
}

标签: c++socketsserver

解决方案


accept()不提供任何超时功能。使用select()or(e)poll()预先检测侦听套接字何时处于可读状态,表明它有一个入站连接等待被接受。这些函数提供超时。例如:

#include <sys/select.h>
#include <sys/time.h>

fd_set readfds;

FD_ZERO(&readfds);
FD_SET(fd, &readfds);

struct timeval timeout;
timeout.tv_sec = 30;
timeout.tv_usec = 0;

if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0)
{
    len = sizeof(client_address);
    int client_fd = accept(fd, (struct sockaddr*) &client_address, &len);
    ...
}
else
{
    // do something else...
}

推荐阅读