我正在尝试使用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()时失败,并且errno为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()body:
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);
}
}
(您可能会注意到我从主沙箱功能中复制了一些东西) 好吧,沙箱总是执行“第一好,第二好”。 我可能会使用“select()”的解决方案,看看它是否有效,但我宁愿理解为什么会出现这种情况。