0

我正在Mini-OS(xen中的操作系统)中编写一个TCP服务器,它可以连接到多个TCP客户端。我编写了一个简单的代码来处理多个 TCP 客户端,但是代码存在问题。问题是我无法让服务器连接三个以上的活动连接。第 4 个或更多客户端因未知原因无法连接。我环顾论坛并尝试增加MEMP_NUM_TCP_PCBin opt.h( stubdom\lwip-x86_64\include\lwip\opt.h ) 的数量限制,但它也没有帮助。

我在Ubuntu上运行 TCP 客户端。根据我所见,第 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;
}
4

1 回答 1

0

我已经解决了这个问题,这是由一个Makefile错误引起的./stubdom,执行后make crossclean,我发现.o文件仍然存在于lwip-x86_64文件夹中。所以我find . -name "*.o" | xargs rm -f在 Makefile 中添加了一个命令,然后一切正常。

原因是lwip configure是由宏定义给出的,宏定义在预编译阶段已经被替换,所以如果我修改lwip configure并且没有删除.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

我该如何解决上述问题?

于 2015-08-24T00:11:44.267 回答