我正在尝试使用UDP(作为练习)运行一个简单的客户端 - 服务器应用程序,OS Linux Mint 14.客户端在启动时向服务器发送请求以获取一些会话参数,包括usec中的超时 . 客户端打开一个套接字并设置一个默认超时值,以便在recvfrom上不被无限制地阻塞,然后发送对这些参数的请求,关闭所述套接字,重新打开设置新超时值的套接字,最后询问用户用于命令 .

参数请求由子函数处理,该子函数除了其他之外还获得指向客户端套接字的指针,因此如果新的sockfd是不同的数字,则主函数也将能够引用新的套接字 . (返回值用作检查值,零或非零)

顺序是:

  • 客户端调用子函数传递套接字指针

  • 子功能发送请求

  • 子功能得到答案

  • 子功能关闭旧套接字

  • 子函数在套接字指针指向的位置打开新的套接字(socket(),setsockopt,bind())(从而替换原文)

- 问题

  • 下一次调用sendto()失败的情况是errno 9(文件编号错误)或errno 88(非套接字上的套接字操作) .

在main中调用函数:(servaddr是一个struct sockaddr_in,因此是强制转换; sockfd是一个int)

int checkParameters;
checkParameters=clientrequest(&sockfd, (struct sockaddr*) &servaddr, 0, settings);

clientrequest()描述:

int clientparameters(int* socketpt, struct sockaddr* remaddr, unsigned int parameters[])

{
unsigned char timeouts = 0;
int received = 0;
socklen_t len;
unsigned char* buff;
if((buff = malloc(MAX_LINE)) == NULL) {
    fprintf(stderr, "Error occurred, process %d, errno %d\n", getpid(), errno);
    return -1;
}
unsigned char i;







    memset(buff, 0, MAX_LINE);
    if(encode(buff, PARAM) < 0) {
        fprintf(stderr, "Error occurred, process %d, errno %d\n", getpid(), errno);
        free(buff);
        return -1;
    }



    if(sendto(*socketpt, buff, 1, 0, remaddr, sizeof(struct sockaddr)) < 0) {
        fprintf(stderr, "Error occurred, process %d, errno %d\n", getpid(), errno);
        free(buff);
        return -1;
    }

    while(received == 0) {


        len = sizeof(struct sockaddr);
        if((received = recvfrom(*socketpt, buff, MAX_LINE, 0, remaddr, &len)) < 0) {

            if(errno == EWOULDBLOCK) {
                if(timeouts == TIMEOUT_NUM) {
                    fprintf(stderr, "Server non found, process %d, errno %d\n", getpid(), errno);
                    free(buff);
                    return -1;
                }
                received = 0;
                timeouts++;


            }
            else {
                fprintf(stderr, "Error occurred, process %d\n errno: %d\n", getpid(), errno);
                free(buff);
                return -1;
            }
        }
    }
}


memcpy(parameters, uncap(buff), sizeof(unsigned int)*3);
/*"uncap" removes user-level protocol header from payload*/

free(buff);



/*Store old socket port + IP address*/
struct sockaddr_in addr;
len = sizeof(struct sockaddr);
if(getsockname(*socketpt, (struct sockaddr*)&addr, &len) < 0) {
    fprintf(stderr, "Error occurred, process %d, errno %d\n", getpid(), errno);
    return -1;
}



if(close(*socketpt) < 0) {
    fprintf(stderr,"Errore occurred, process %d, errno %d\n", getpid(), errno);
    return -1;
}

/*Opens new socket*/
if(((*socketpt) = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    fprintf(stderr, "Error occurred, process %d, errno %d\n", getpid(), errno);
    return -1;
}


/*Set timer*/
struct timeval t;
t.tv_usec = parameters[2]; //Where timer is set

if(setsockopt(*socketpt, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval)) < 0 ) {
    fprintf(stderr, "errno: %d\n win: %u\t loss: %u\t timeout: %u\n\n", errno, parameters[0], parameters[1], parameters[2]);
    fprintf(stderr, "Error occurred, process %d, errno %d\n", getpid(), errno);
    if(close(*socketpt) < 0) {
        fprintf(stderr, "Errore in close() in clientrequest(), processo %d, errno %d\n", getpid(), errno);
    }
    return(-1);
}

if(bind(*socketpt, (struct sockaddr*)&addr, sizeof(struct sockaddr)) < 0) {
    fprintf(stderr, "Error occurred, process %d, errno %d\n", getpid(), errno);
    if(close(*socketpt) < 0) {
        fprintf(stderr, "Error occurred, process %d, errno %d\n", getpid(), errno);
    }
    return(-1);
}

return 0;

}

一旦我输入第二个请求函数,它在第一个sendto()失败,错误为88 .

这是我尝试过的一些沙盒代码 . 它基本上遵循相同的socket(),setsockopt(),bind(),sendto(),close()方法,除了“sendto”发送到套接字绑定的相同IP /端口 .

int* receptionfd = malloc(4);

struct sockaddr_in addr;
char buff[MAX_LINE];

int n;
unsigned int len;


if((*receptionfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    perror("Error occurred\n");
    free(receptionfd);
    exit(-1);
}

memset((void*)&addr, 0, sizeof(addr));


addr.sin_family = AF_INET;

if(inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) <= 0) {
    perror("Errore occurred\n");
    free(receptionfd);
    exit(-1);
}

addr.sin_port = htons(5050);


struct timeval t;
t.tv_usec = 20000;

if(setsockopt(*receptionfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval)) < 0 ) {
    fprintf(stderr, "Error occurred, process %d, errno %d\n", getpid(), errno);
    if(close(*receptionfd) < 0) {
        fprintf(stderr, "Error occurred, process %d, errno %d\n", getpid(), errno);
    }
    return(-1);
}



if(bind(*receptionfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
    perror("Error occurred\n");
    free(receptionfd);
    exit(-1);
}


if(sendto(*receptionfd, buff, 0, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr)) < 0) {
    fprintf(stderr, "Error occurred, first sendto(), errno %d\n", errno);
    free(receptionfd);
    exit(-1);
}
else
    printf("First good\n");

close(*receptionfd);

createsock(receptionfd, addr);

if(sendto(*receptionfd, buff, 0, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr)) < 0) {
    fprintf(stderr, "Error occurred, second sendto(), errno %d\n", errno);
    free(receptionfd);
    exit(-1);
}
else {
    printf("Second good\n");
}

close(*receptionfd);
free(receptionfd);
exit(0);

createsock()体:

void createsock(int* receptionfd, struct sockaddr_in addr) {
if(((*receptionfd) = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
            perror("Error occurred\n");
            free(receptionfd);
            exit(-1);
    }

    memset((void*)&addr, 0, sizeof(addr));


    addr.sin_family = AF_INET;

    if(inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) <= 0) {
        perror("Error occurred\n");
        free(receptionfd);
        exit(-1);
    }

    addr.sin_port = htons(5050);



    struct timeval t;
    t.tv_usec = 20000;

    if(setsockopt(*receptionfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval)) < 0 ) {
        fprintf(stderr, "Error occurred, process %d, errno %d\n", getpid(), errno);
        if(close(*receptionfd) < 0) {
            fprintf(stderr, "Error occurred, process %d, errno %d\n", getpid(), errno);
        }
    }


    if(bind(*receptionfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("Error occurred\n");
        exit(-1);
    }

}

(您可能会注意到我从主沙箱功能中复制了一些东西)好吧,沙箱总是执行“First good,Second good” . 我可能会使用“select()”来解决它是否有效,但我宁愿理解为什么会这样做 .