我有一个在非并发单进程实现中具有TCP套接字的服务器。
int main(int argc, char** argv) {
int sock_ds, acc_sock_ds, opt, client_addr_l;
unsigned short port;
struct sockaddr_in server_addr, client_addr;
/*Parsing command line: port-number retrieving*/
/*...*/
printf("Port number retrieved (%d), server is starting ...\n", port);
/*TCP Socket creation*/
sock_ds = socket(AF_INET, SOCK_STREAM, 0);
if(sock_ds == -1){
fprintf(stderr, "Socket creation error\n");
exit(EXIT_FAILURE);
}
/*Server address binding*/
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
//use setsockopt(2) with OS_REUSEADR ???
if(bind(sock_ds, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){
fprintf(stderr, "Address binding error\n");
exit(EXIT_FAILURE);
}
/*Server with passive socket*/
if(listen(sock_ds, SOMAXCONN) == -1){
fprintf(stderr, "Listen call error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
printf("Server is ready. Waiting for connections.\n");
/*Busy-waiting server*/
while(1){
memset(&client_addr, 0, sizeof(client_addr));
acc_sock_ds = accept(sock_ds, &client_addr, &client_addr_l);
/*Connect error management*/
if(acc_sock_ds == -1){
errsv = errno;
if(errsv == 12 || errsv == 23 ){
/*Fatal errors ENOMEM, ENFILE*/
fprintf(stderr, "Fatal error on accept\n");
exit(EXIT_FAILURE);
}
else if(errsv == 103 || errsv == 4 || errsv == 71 || errsv == 92
|| errsv == 112 || errsv == 113 || errsv == 95 || errsv == 101)
/*ECONNABORTED, EINTR, EPROTO, ENOPROTOOPT,
* EHOSTDOWN, EHOSTUNREACH, EOPNOTSUPP, ENETUNREACH*/
continue;
else if(errsv == 100 || errsv == 64){
/* ENETDOWN - ENONET */
/*start timeout...*/
continue;
}
}
}
}在此测试中,我预计服务器将继续调用accept(2),同时也会出现故障。我知道有一些终端错误情况,比如EBADF。我是否应该根据errno的值提供不同的行为(进程的终止)?对于哪些值,服务器必须停止,而哪些值可能会继续等待?
代码已编辑。我从来没有让通过errno来处理错误。如果有错误或建议,请通知他们。我注意到,网络的缺失暗示了ENETDOWN - ENONET这两个条件。对于这些情况,我应该预料到超时以防止停滞吗?
发布于 2013-03-03 04:29:43
查看在MacOS X上记录的accept(2)错误代码(对于大多数兼容POSIX的系统,这些错误代码应该是一致的):
EBADF -程序员错误-如果原始套接字调用succeededECONNABORTED -尝试againEFAULT -程序员错误-不可能发生,除非套接字被invalidEINTR -调用中断,尝试againEINVAL -“socket不愿意接受连接”-我不确定这将如何发生。这可能是由于没有首先调用FD(程序员错误),尽管在某些操作系统上,这也可能是由于程序员error)EMFILE -程序员错误-您耗尽了每个进程的FD,但除非您忘记关闭themENFILE -系统耗尽FDs这可能是fatalENOMEM -系统内存耗尽-这可能是fatalENOTSOCK -程序员错误-不可能发生,除非您忘记关闭listen(2) -这可能是namelen参数为负您传递了一个不是socketEOPNOTSUPP的FD -程序员错误-除非您传递的套接字不是SOCK_STREAMEWOULDBLOCK -程序员错误-您的套接字被配置为non-blocking此外,Linux系统似乎还可以生成ENETDOWN、EPROTO、ENOPROTOOPT、EHOSTDOWN、ENONET、EHOSTUNREACH、EOPNOTSUPP和ENETUNREACH。这些是您应该循环查找的网络错误。
总而言之,您可能应该:
在调试任何其他内容时,
assert()中退出ECONNABORTED或EINTR上的ENFILE或EINTR程序以及上面的列表-这些运行时错误应该只会由于代码中的逻辑错误而发生,而不会因为与网络相关的事件而发生。发布于 2013-03-03 20:23:34
风格:
顺便说一句:下面的大多数符号常量似乎并不存在。
#include <errno.h>
#include <strings.h>
/* Busy-waiting server */
while(1){
memset(&client_addr, 0, sizeof(client_addr));
acc_sock_ds = accept(sock_ds, &client_addr, &client_addr_l);
/*Connect error management*/
if(acc_sock_ds == -1){
switch(errsv=errno) {
/*Fatal errors ENOMEN, ENFILE, all others*/
default :
case ENOMEM :
case ENFILE :
fprintf(stderr, "Fatal error on accept %d(%s)\n"
, errsv, strerror(errsv)
);
exit(EXIT_FAILURE);
/* normal NON-ERROR error conditions */
case ECONNABORTED :
case EINTR :
case EPROTO :
case ENOPROTOOPT :
case EHOSTDOWN :
case EHOSTUNREACH :
case EOPNOTSUPP :
case ENETUNREACH :
continue;
case ENETDOWN :
case ENONET :
/*start timeout...*/
continue;
}
}
}
}https://stackoverflow.com/questions/15178800
复制相似问题