Не удается получить более 3 активных TCP-соединений в Mini-OS?

Я пишу сервер TCP в Mini-OS (операционная система в xen), он может подключаться к нескольким клиентам TCP. Я написал простой код для работы с несколькими клиентами TCP, но с этим кодом возникла проблема. Проблема в том, что я не могу заставить сервер подключать более трех активных соединений. 4-й или более клиентов не могут подключиться по неизвестным причинам. Я просмотрел форумы и попытался увеличить лимит количества для MEMP_NUM_TCP_PCB в opt.h (stubdom\lwip-x86_64\include\lwip\opt.h), и это тоже не помогло.

Я запускаю TCP-клиент на Ubuntu. Судя по тому, что я видел, 4-й клиент действительно был подключен, но во время "write" function: "Resolver Error 0 (no error)" возникло исключение.

Как я могу решить эту проблему?

//server code 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MYPORT 1234    // the port users will be connecting to
#define BACKLOG 2// how many pending connections queue will hold
#define BUF_SIZE 1024
int fd_A[BACKLOG];    // accepted connection fd
int conn_amount;      // current connection amount
void showclient()
{
    int i;
    printf("-----> client amount: %d\n", conn_amount);
    for (i = 0; i < BACKLOG; i++) {
        printf("BACKLOG%d ---> fd = %d\n", i, fd_A[i]);
    }
    printf("\n\n");
}
int main(void)
{
    sleep(1);
    printf("start server\n");
    int sock_fd, new_fd;             // listen on sock_fd, new connection on new_fd
    struct sockaddr_in server_addr;  // server address information
    struct sockaddr_in client_addr;  // connector's address information
    socklen_t sin_size;
    int yes = 1;
    char buf[BUF_SIZE];
    int ret;
    int i;
    if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }
    //if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
    /*if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
        //perror("setsockopt");
        //exit(1);
    }
    if (fcntl(sock_fd, F_SETFL, O_NONBLOCK) == -1) {
    printf("Set server socket nonblock failed\n");
    exit(1);
    }*/
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;         // host byte order
    server_addr.sin_port = htons(MYPORT);     // short, network byte order
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // automatically fill with my IP
    //memset(server_addr.sin_zero, '0', sizeof(server_addr.sin_zero));
    if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        exit(1);
    }
    printf("listen...\n");
    if (listen(sock_fd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }
    printf("listen port %d\n", MYPORT);
    fd_set fdsr, wfds, efds;
    int maxsock;
    struct timeval tv;
    conn_amount = 0;
    sin_size = sizeof(client_addr);
    maxsock = sock_fd;
    while (1) 
    {
    sleep(1);  // it's necessary
        // initialize file descriptor set
        FD_ZERO(&fdsr);
    FD_ZERO(&wfds);
        //FD_ZERO(&efds);
        FD_SET(sock_fd, &fdsr);  // add fd
        FD_SET(sock_fd, &wfds);  // add fd
        //FD_SET(sock_fd, &efds);  // add fd
        // timeout setting
        tv.tv_sec = 30;
        tv.tv_usec = 0;
        // add active connection to fd set
        for (i = 0; i < BACKLOG; i++) {
            if (fd_A[i] != 0) {
                FD_SET(fd_A[i], &fdsr);
            }
        }
    //printf("before select!!!!!!!!!!!! ret = %d\n", ret);
    if ((select(maxsock + 1, &fdsr, &wfds, (fd_set*) 0, (struct timeval*) 0)) < 0) {
            perror("select");
            break;
        } 

        // check every fd in the set
        for (i = 0; i < conn_amount; i++) 
        {
            if (FD_ISSET(fd_A[i], &fdsr)) // check which fd is ready
            {
                ret = recv(fd_A[i], buf, sizeof(buf), 0);
                if (ret <= 0) 
                {        // client close
                    printf("ret : %d and client[%d] close\n", ret, i);
                    close(fd_A[i]);
                    FD_CLR(fd_A[i], &fdsr);  // delete fd 
                    fd_A[i] = 0;
                    conn_amount--;
                }
                else 
                {        // receive data
                    if (ret < BUF_SIZE)
                        memset(&buf[ret], '\0', 1); // add NULL('/0')
                    printf("client[%d] send:%s\n", i, buf);
                }
            }
        }
    // check whether a new connection comes
        if (FD_ISSET(sock_fd, &fdsr))  // accept new connection 
        {
            new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size);
            if (new_fd <= 0) 
            {
                perror("accept");
                continue;
            }
            // add to fd queue
            if (conn_amount < BACKLOG) 
            {
                fd_A[conn_amount++] = new_fd;
                printf("------> new connection client[%d] %s:%d\n", conn_amount,
                        inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
                if (new_fd > maxsock)  // update the maxsock fd for select function
                    maxsock = new_fd;
            }
            else 
            {
                printf("max connections arrive, exit\n");
                send(new_fd, "bye", 4, 0);
                close(new_fd);
                break;   
            }
        }
        //showclient();
    }
    // close other connections
    for (i = 0; i < BACKLOG; i++) 
    {
        if (fd_A[i] != 0) 
        {
            close(fd_A[i]);
        }
    }
    exit(0);
}

//client code
#include   <sys/stat.h>   
#include   <sys/types.h>   
#include   <sys/socket.h>   
#include   <stdio.h>   
#include   <malloc.h>   
#include   <netdb.h>   
#include   <fcntl.h>
#include   <unistd.h>
#include   <netinet/in.h>
#include   <arpa/inet.h>
#include   <string.h>
#define    RES_LENGTH  10240 
int     connect_socket(char * server,int serverPort);
int     send_msg(int sockfd,char * sendBuff);
char *  recv_msg(int sockfd);
int     close_socket(int sockfd);
int main(int argc, char ** argv)
{
    int   sockfd[1024] = {0};
    char  sendMsg[30]="zhangchengfei\r\n\r";
    char* res;
    int   port = 1234;
    char  ip[128] = {0};
    strncpy(ip, "10.107.19.62", 128);
    if(argc > 2)
    {
        strncpy(ip, argv[1], 128);
        port = atoi(argv[2]);
        printf("Input IP: %s, port : %d\n", ip, port);
    }
    else if(argc > 1)
    {   
        //port = atoi(argv[1]);
        //printf("Input port : %d\n", port);
    //
    int num_client = atoi(argv[1]);
    int i = 0;
    for (i = 0; i <= num_client; i++) {
        printf("start connect %d\n", i + 1);           
        sockfd[i]=connect_socket(ip, port);
        printf("connect %d OK\n", i + 1);   
        getchar();
    }
    for (i = 0; i <= num_client; i++) {
        send_msg(sockfd[i], sendMsg);
        /* res=recv_msg(sockfd); */

        printf("client %d send msg = %s\n", i + 1, sendMsg);
        //printf(res);
        //free(res);
        getchar();
    }
    for (i = 0; i <= num_client; i++) {
        close_socket(sockfd[i]);
        printf("close socket %d\n", i + 1);
        }
    }
    return 0;
}

int    connect_socket(char * server,int serverPort){
    int    sockfd=0;
    struct    sockaddr_in    addr;
    struct    hostent        * phost;

    if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0){
        herror("Init socket error!");
        return -1;
    }
    bzero(&addr,sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(serverPort);
    addr.sin_addr.s_addr = inet_addr(server);

    if(addr.sin_addr.s_addr == INADDR_NONE){
        phost = (struct hostent*)gethostbyname(server);
        if(phost==NULL){
            herror("Init socket s_addr error!");
            return -1;
        }
        addr.sin_addr.s_addr =((struct in_addr*)phost->h_addr)->s_addr;
    }
    if(connect(sockfd,(struct sockaddr*)&addr, sizeof(addr))<0)
    {
        perror("Connect server fail!");
        return -1; 
    }
    else
        return sockfd;
}


int send_msg(int sockfd,char * sendBuff)
{
    int sendSize=0;
    if((sendSize=send(sockfd,sendBuff,strlen(sendBuff),0))<=0){
        herror("Send msg error!");
        return -1;
    }else
        return sendSize;
}


char* recv_msg(int sockfd){
    char * response;
    int  flag=0,recLenth=0;
    response=(char *)malloc(RES_LENGTH);
    memset(response,0,RES_LENGTH);

    for(flag=0;;)
    {
        printf("======recv data:\n");
        if(( recLenth=recv(sockfd,response+flag,RES_LENGTH-flag,0))==-1 )
        {
            free(response);
            printf("Return value : %d\n", recLenth);
            perror("Recv msg error : ");
            return NULL;
        }
        else if(recLenth==0)
            break;
        else
        {
            printf("%d char recieved data : %s.\n", recLenth, response+flag);
            flag+=recLenth;
            recLenth=0;
        }
    }
    printf("Return value : %d\n", recLenth);
    response[flag]='0';
    return response;
}


int close_socket(int sockfd)
{
    close(sockfd);
    return 0;
}

person Aaron    schedule 23.08.2015    source источник
comment
И соответствующий код будет? Что вы пытались сузить проблему?   -  person hagello    schedule 23.08.2015
comment
В первом предложении вы пишете, что сервер подключается к нескольким клиентам. В 3-м предложении говорится, что 4-й клиент не может подключиться. Так кто запускает соединение? И сервер и клиенты?   -  person hagello    schedule 23.08.2015
comment
Я обнаружил, что файл opt.h настраивает некоторую рабочую среду программы, хотя я изменил значения некоторых параметров, это не сработало! 3-й клиент начинает подключение к серверу в порядке, 4-й не удалось.   -  person Aaron    schedule 24.08.2015


Ответы (1)


Я решил эту проблему, вызванную ошибкой Makefile в ./stubdom, после выполнения make crossclean я обнаружил, что файлы .o все еще существуют в папке lwip-x86_64. Поэтому я добавляю команду find . -name "*.o" | xargs rm -f в Makefile, и тогда все в порядке.

Причина в том, что конфигурация lwip задается определением макроса, определение макроса было заменено на этапе предварительной компиляции, поэтому, если я изменю конфигурацию lwip и не удалю файлы .o, эффекта не будет. Ниже приведены определения макросов, которые я изменил в opt.h.

    MEMP_NUM_TCP_PCB 100
    MEMP_NUM_TCP_PCB_LISTEN 100
    MEMP_NUM_NETCONN 100

Теперь сервер может преодолеть ограничения на подключение, и можно установить более 3 активных TCP-соединений, но, к сожалению, мы столкнулись с другой проблемой: серверная сторона может получить только 61 клиента запросов на подключение. При превышении количества клиентов об ошибке на стороне сервера будет сообщено следующим образом:

    ASSERTION FAILED: mbox->reader != mbox->writer at lwip-arch.c:124.
    Do_exit called!
    base is 0x29fe78 caller is 0x4d49d
    base is 0x29fe98 caller is 0x5a05a
    base is 0x29fec8 caller is 0x5a153
    base is 0x29fef8 caller is 0x634a1
    base is 0x29ff28 caller is 0x65074
    base is 0x29ff78 caller is 0x5d0dd
    base is 0x29ffc8 caller is 0x59822
    base is 0x29ffe8 caller is 0x33da

Как я могу решить вышеуказанную проблему?

person Aaron    schedule 24.08.2015