我在非并发单进程实现中有一个带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
。我是否应该期望这些情况超时以防止停滞?
答案 0 :(得分:2)
查看MacOS X上为accept(2)
记录的错误代码(对于大多数符合POSIX标准的系统,它应该是一致的):
EBADF
- 程序员错误 - 如果原始socket
调用成功则无法发生ECONNABORTED
- 再试一次EFAULT
- 程序员错误 - 除非&client_addr
无效EINTR
- 呼叫中断,再试一次EINVAL
- “套接字不愿接受连接” - 我不确定会发生什么情况。 可能是由于没有先调用listen(2)
(程序员错误),尽管在某些操作系统上显然也可能是namelen
参数为负(也是程序员错误)< / LI>
EMFILE
- 程序员错误 - 你用完了每个进程的FD,但除非你忘了关闭它们,否则不会发生这种情况ENFILE
- 系统耗尽了FD - 这可能是致命的ENOMEM
- 系统内存耗尽 - 这可能是致命的ENOTSOCK
- 程序员错误 - 除非你传递的是非套接字的FD,否则不会发生EOPNOTSUPP
- 程序员错误 - 除非你传递的插座不是SOCK_STREAM
EWOULDBLOCK
- 程序员错误 - 您的套接字已配置为非阻止此外,Linux系统似乎还可以生成ENETDOWN
,EPROTO
,ENOPROTOOPT
,EHOSTDOWN
,ENONET
,EHOSTUNREACH
, EOPNOTSUPP
和ENETUNREACH
。这些是你应该循环的网络错误。
总之,你应该:
ENFILE
或ENOMEM
ECONNABORTED
和EINTR
,以及上面的列表来自Linux assert()
- 这些运行时错误应该只是由于代码中的逻辑错误而发生,而不是因为与网络相关的事件。答案 1 :(得分:1)
文体:
#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;
}
}
}
}