网络编程-一个简单的echo程序(2)

前言

在《网络编程-一个简单的echo程序(0)》和《网络编程-一个简单的echo程序(1)》中分别介绍了echo程序的整体流程和用到的数据结构与函数。本文将结合两者,来看实际使用过程中,有哪些基本的异常场景。

Protocol not supported

不支持的协议类型。前面在介绍socket函数的时候说到,TCP仅支持字节流套接字,UDP仅支持数据报套接字,如果你的第二个参数选择了SOCK_STREAM,即字节流套接字,而第三个参数选择了IPPROTO_UDP,那么将会出现不支持的协议错误。示例程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//来源 公众号【编程珠玑】 源网站:https://www.yanbinghu.com
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
int main(void)
{
int socktfd = socket(AF_INET,SOCK_STREAM,IPPROTO_UDP);
if(-1 == socktfd)
{
perror("socket failed");
}
return 0;
}

运行结果:

1
socket failed: Protocol not supported

由于socket函数返回的是一个套接字描述符,因此它和打开文件一样,如果打开的数量到了一定的限度,也会出现失败。

除此之外,如果系统不支持某种协议族,例如不支持AF_KEY ,会出现:

1
Operation not permitted

的错误。

Cannot assign requested address

ip不存在。这种错误很容易模拟,还是用前文提到的server程序:

1
2
$ ./server 192.168.3.4 1055
bind error: Cannot assign requested address

由于192.168.3.4并不是我本机的ip,因此在bind的时候必然会出错。

address is already in use

端口已被占用,或者上一个没有停止。例如已经在一个终端启动了server,然后再次启动:

1
2
$ ./server
bind error: Address already in use

或者连接之后,server处于TIME_WAIT状态,此时再次启动server也会遇到相同的问题。

关于TIME_WAIT状态,在《网络编程-再看TCP的四次挥手》中有详细的论述,本文不再赘述。

permission denied

出现这种错误的情况比较多,通常都是权限问题导致的,例如普通用户试图在1024以内的端口监听:

1
2
$ ./server 127.0.0.1 1000
bind error: Permission denied

由于普通用户只能绑定使用1024以外的端口,因此当普通用户试图使用1024以内的端口时,就会提示Permission denied。

Permission denied的情况有很多种,这里只列举了其中一种。

Bad file descriptor

这种错误在很多场景下会出现,因为我们在很多地方都用到了套接字描述符,因此一旦套接字描述符相关参数错误,都会出现这种错误,例如我们将bind的第一个参数随便指定一个值,并运行server:

1
2
$ ./server
bind error: Bad file descriptor

Connection refused

这个错误常常出现于连接到一个未监听的地址,例如:

1
2
$ ./client 127.0.0.1 8888
connect failed: Connection refused

这种情况下表明TCP连接的过程中收到了RST响应,有可能是8888端口没有监听,也可能是别的原因导致连接取消。

Connection timed out

这个错误常常是由于远端服务器过于繁忙,没有accept。这个我们已经在TCP连接的建立一文中有说明,一旦服务端的连接队列满,将不会处理新的连接请求,客户端将会超时。

当然除此之外,如果指定连接到一个不存在的IP地址:

1
2
$ ./client 192.168.183.5 8888
connect failed: Connection timed out

前面描述的情况只是很多情况的一两种,最终原因都是客户端没有收到SYN的响应,例如主机防火墙设置了端口不可访问,也可能导致出现这种情况。

如果是远端不可达的IP地址,将会收到主机不可达的ICMP错误:

1
2
$ ./client 192.168.0.5 8888
connect failed: No route to host

总结

本文列出了在进行网络编程中最常遇到的错误,但是还有很多错误未曾提出;除此之外,某种错误出现的场景也并没有完全指出,但对于分析常见问题基本足够。当然也欢迎在留言区补充分享。

守望 wechat
关注公众号[编程珠玑]获取更多原创技术文章
出入相友,守望相助!