inet_addr()和htonl()结合使用引发的connect()超时
来源:互联网 发布:java的书会过时吗 编辑:程序博客网 时间:2024/06/05 15:50
Tcp通信使用的是网络字节序,所以一般都需要htonl()把ip地址转换成网络字节序,但如果ip已经是网络字节序了,再调用htonl就会导致不再是网络字节序了,引发严重后果,就是connect或者使用了一个相反的ip
上代码
服务端:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h> /* See NOTES */#include <sys/socket.h>#include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <errno.h>#include <unistd.h>extern int errno;int main(){int domain = AF_INET;int type = SOCK_STREAM;int protocol = 0;int ret = -1;int nListenFd = -1;int nNewClientFd = -1;short int port = 2000; struct sockaddr_in addr_in;int backlog = 128; // 默认是128int len = 0;char chBuffer[1024] = {0};int flags = 0;nListenFd = socket( domain, type, protocol);if(nListenFd < 0){printf("\n socket failed ! errno[%d] err[%s]\n", errno, strerror(errno));return -1;}memset(&addr_in, 0, sizeof(struct sockaddr_in));addr_in.sin_family = AF_INET;addr_in.sin_port = htons(port);//htons的返回值是16位的网络字节序整型数 htons尾的字母s代表shortaddr_in.sin_addr.s_addr = htonl(INADDR_ANY);ret = bind(nListenFd, ( struct sockaddr * )(&addr_in), sizeof(struct sockaddr_in)); if(ret < 0) { printf("\n bind failed ! errno[%d] err[%s]\n", errno, strerror(errno)); close(nListenFd); //避免资源泄漏return -1;} ret = listen(nListenFd, backlog); if(ret < 0) {printf("\n listen failed ! errno[%d]err[%s]\n", errno, strerror(errno));close(nListenFd); //避免资源泄漏return -1;}nNewClientFd = accept(nListenFd, ( struct sockaddr *)NULL, NULL); //阻塞模式if(nNewClientFd < 0){printf("\n accept failed ! errno[%d]err[%s]\n", errno, strerror(errno));close(nListenFd); //避免资源泄漏return -1;}printf("\n new client [%d] \n",nNewClientFd);close(nNewClientFd);close(nListenFd);return 0;}
有问题的客户端:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h> /* See NOTES */#include <sys/socket.h>#include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <errno.h>#include <unistd.h>extern int errno;int main(){int domain = AF_INET;//AF_INETint type = SOCK_STREAM;int protocol = 0;int ret = -1;int nClientFd = -1;short int port = 2000; struct sockaddr_in addr_in;int len = 0;char chBuffer[1024] = {0};int flags = 0;char * pchServerIP = "192.168.1.211";nClientFd = socket( domain, type, protocol);if(nClientFd < 0){printf("\n socket failed ! errno[%d] err[%s]\n", errno, strerror(errno));return -1;} memset(&addr_in, 0, sizeof(struct sockaddr_in));addr_in.sin_family = AF_INET;addr_in.sin_port = htons(port);//htons的返回值是16位的网络字节序整型数 htons尾的字母s代表shortaddr_in.sin_addr.s_addr = htonl(inet_addr(pchServerIP)); //错误的做法//addr_in.sin_addr.s_addr = inet_addr(pchServerIP); ret = connect(nClientFd, ( struct sockaddr * )(&addr_in), sizeof(struct sockaddr_in)); if(ret < 0) { printf("\n connect failed ! errno[%d] err[%s]\n", errno, strerror(errno)); close(nClientFd); //避免资源泄漏return -1;}printf("\n connect success ! \n");close(nClientFd);return 0;}
编译:
gcc simple_server.c -g -o simple_server
gcc simple_client.c -g -o simple_client
先启动服务器,并使用strace去追踪调用
strace ./simple_server
服务器一直阻塞,等待连接
客户端:
本来客户端是要去connect 192.168.1.211 ,结果被搞成了去connect 211.1.168.192,因此活该connect超时啊
改正方法:
客户端的代码
把addr_in.sin_addr.s_addr = htonl(inet_addr(pchServerIP));
改成addr_in.sin_addr.s_addr = inet_addr(pchServerIP);即可
顺便说以下这个inet_addr函数
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
The inet_addr() function converts the Internet host address cp from IPv4 numbers-and-dots notation into binary data in
network byte order. If the input is invalid, INADDR_NONE (usually -1) is returned. Use of this function is problematic
because -1 is a valid address (255.255.255.255). Avoid its use in favor of inet_aton(), inet_pton(3), or getaddrinfo(3),
which provide a cleaner way to indicate error return.
inet_addr() 函数把字符串ip转换成具有网络字节序的二进制ip地址了,因此不要再画蛇添足,再调用htonl再转一次网络字节序了,后果很严重。
当然文档提示这个函数也不是很好,就是返回-1的时候的ip地址会是255.255.255.255
- inet_addr()和htonl()结合使用引发的connect()超时
- htonl() htons()及inet_ntoa() inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法 .
- htonl() 、htons()及inet_ntoa() 、inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法
- htonl() htons()及inet_ntoa() inet_addr()的用法
- level和 connect by 的结合使用
- Htonl 引发的Big Endian 和 Little Endian
- Android Device Monitor 文件管理的常见问题
- 石乙己——孔乙己程序员版
- java中停止线程执行的方法
- 查找字符个数--查找一个字符串中第一个只出现两次的字符。比如:“abcdefabcdefabc”中第一个只出现两次为‘d’,要求时间复杂度为O(N),空间复杂度为O(1)
- java BIO,NIO在单服务器,多客户端通信上的应用
- inet_addr()和htonl()结合使用引发的connect()超时
- 配置无线网卡和有线网卡分别上内外网的方法
- SQL数据库的ACID含义
- ubuntu16.04——设置python3为默认及库的安装
- jstree-初始化时默认选中根节点
- Listview+适配器
- 矩阵不可逆的充分必要条件
- ListView两级联动
- MVC框架