之所以把对异常信息的介绍放到原理之前讲,是因为由于socket本身的复杂性,导致了产生各种异常的复杂性。我们应该时刻铭记的是,sokcet本身属于系统(OS),是系统对TCP/IP的实现,也就是说,socket发出的异常信息不代表程序出错,甚至不代表系统出错,而仅仅就是代表socket本身的各种异常情况。另外一点我觉得应该强调的是:socket不是TCP/IP;TCP/IP也不是socket。socket是为广泛的协议设计的,涉及TCP/IP的内容只是socket体系中一个很小的子集;而TCP/IP就更加独立于sokcet而存在——TCP/IP是协议描述;socket是对协议理论的一种实现形式。
因为socket是属于系统的,所以不同的系统对于socket有着大同小异的解释,出错描述也不尽相同。在Linux中,socket的异常信息可以通过errno获得(int类型),然后可以通过函数strerror()将int转换成字符串描述;也可以通过函数perror()直接获得其描述。
要使用errno需要包含头文件<errno.h>。我建议使用errno获得int类的错误信息的一个重要原因在于,socket的异常不一定就必然导致程序终止。Bjarne Stroustrup在介绍C++异常机制的时候对C风格的异常机制有着这样的描述:(C++对于异常)的默认响应方式是终止程序。传统的反应(对于发生异常的时候)则是装糊涂,接着做下去,以期得到最好的结果。不过以我目前的水平看来,终止正在进行的程序然后再通过异常机制重新启动一个新的流程,其代价远远大于“装糊涂”的让程序继续运行下去,只要错误不是致命的,通过简单的判断和处理或许效果更佳。
例如,socket中就有一个很有代表性的情况,在TCP连接中,如果一方意外退出——也就是说没有通过TCP退出流程退出,比如没有运行完程序关闭掉socket而直接X掉或者Ctrl+c了。socket往往会因为recv()返回值小于0而抛出一个异常。正常断开连接的时候,recv()会通过返回0表示连接已经断开,但是大多数时候,我们并不希望因为异常的断开就导致另外一端的程序终止(想象一下如果你关掉QQ腾讯的服务器程序就终止是什么概念……),所以我们必须处理这种情况。
在Linux中,远程连接异常断开(被重置)的errno代码是104,类似的,我们应该保证出现这种异常的时候程序可以继续运行。
- //Filename: SockClass.hpp
- #ifndef SOCK_CLASS_HPP
- #define SOCK_CLASS_HPP
- #include <unistd.h>
- #include <iostream>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <errno.h>
- namespace sockClass
- {
- void error_info(const char* s);
- }
以上是头文件中的声明,下面是函数,我们这里仅仅演示处理了104错误。
- namespace sockClass
- {
- void error_info(const char* s)
- {
- int err_info = errno;
- std::cerr << strerror(err_info) << ": errno: " << err_info << std::endl;
- if (err_info == 104){
- return;
- }
- exit(1);
- }
- }
在windows中,错误代码由WSAGetLastError()获得,而无需设置errno。
- //Filename: SockClass.hpp
- #ifndef SOCK_CLASS_HPP
- #define SOCK_CLASS_HPP
- #include <iostream>
- #include <winsock2.h>
- namespace sockClass
- {
- void error_info(const char* s);
- }
WinSock的错误代码跟Linux中的不一样,同样的异常,WinSock的错误代码是10054。
并且,由于没有errno也就无从调用strerror(),我们最好自己写出详细的异常信息。
WinSock的详细代码信息在这里:
http://msdn.microsoft.com/en-us/library/ms740668(v=VS.85).aspx
Win32下的演示代码如下:
- namespace sockClass
- {
- void error_info(const char* s)
- {
- int winsock_err = WSAGetLastError();
- perror(s);
- std::cerr << "WinSock Error: " << winsock_err << std::endl;
- if (winsock_err == WSAECONNRESET) {
- std::cerr << "Connection reset by peer." << std::endl;
- return;
- }
- exit(1);
- }
- }
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。