socket编程之bind()函数使用示例详解

Rayna ·
更新时间:2024-11-01
· 437 次阅读

目录

正文

端口号具体是怎么绑定

老代码

端口被占用的问题解决

正文

当你创建了socket之后,你会想要把这个socket和你本机上的某个端口号(port)进行关联。

端口号是内核用来确认将收到的数据包交给哪个具体进程的socket descriptor的依据。

通常在写服务端程序的时候我们才需要进行关联,客户端程序不需要我们手动绑定端口,直接connect()就好了。

端口号具体是怎么绑定 #include <sys/types.h> #include <sys/socket.h> int bind(int sockfd, struct sockaddr *my_addr, int addrlen);

sockfdsocket()返回的一个socket file descriptormy_addr是一个指向包含了你的端口号和IP地址信息的struct sockaddr指针;addrlen是以字节为单位的地址长度。

接下来,我们给出一个例子,它将socket和我本机的3490端口进行绑定:

struct addrinfo hints, *res; int sockfd; // first, load up address structs with getaddrinfo(): memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // fill in my IP for me getaddrinfo(NULL, "3490", &hints, &res); // make a socket: sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); // bind it to the port we passed in to getaddrinfo(): bind(sockfd, res->ai_addr, res->ai_addrlen);

通过使用AI_PASSIVE标识,程序会自动绑定它所在的程序的IP。如果你想精确绑定到本机的某一个IP地址,你就不能用AI_PASSIVE了,而且你还得把getaddrinfo()的第一个参数从NULL改为你想绑定的那个IP地址。

bind()和其他系统调用一样,发生错误的时候返回-1,并且会设置全局变量errno的值。

很多老代码都会在调用bind()之前手动封装 struct sockaddr_in 。当然,这里绑定的肯定是IPv4的地址,如果你想使用IPv6,你照样可以手动封装struct sockaddr_in6 ,但是极力不推荐你这么做。你还是应该老老实实用 getaddrinfo() ,这样更优雅、更简单。

老代码 // !!! THIS IS THE OLD WAY !!! int sockfd; struct sockaddr_in my_addr; sockfd = socket(PF_INET, SOCK_STREAM, 0); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(MYPORT); // short, network byte order my_addr.sin_addr.s_addr = inet_addr("10.12.110.57"); memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero); bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr);

上面这个代码中,你依然可以把my_addr.sin_addr.s_addr设置为 INADDR_ANY ,它的作用上文提到的AI_PASSIVE一样,都会让代码自动绑定到本机IP。 INADDR_ANY 的IPv6版本是一个全局变量,叫in6addr_any,这个变量会被指定给你的 struct sockaddr_in6sin6_addr字段。

你也可以使用IN6ADDR_ANY_INIT这个宏来初始化变量

调用bind()时有一件事需要你特别注意:不要使用1024以下的端口号,因为这些端口号是被保留使用的,除非你是超级管理员。除了1024以下的,1025~65535之间的随便用(其他程序占用的除外)。

有时候,你明明重新运行了你的服务端程序,但是bind()报错了,提示你“Address already in use”。这是为什么?理论上重启之后端口就会被释放啊!好吧,这是因为有一些连接到socket的连接还悬在内核中,就是它们占用了这个端口号。

端口被占用的问题解决

你可以等一分钟左右让它们自行消失,或者在你的代码加这么几行:

int yes=1; //char yes='1'; // Solaris people use this // lose the pesky "Address already in use" error message if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof yes) == -1) { perror("setsockopt"); exit(1); }

这样就不会再出现端口被占用的问题了。

以上就是socket编程之bind()函数使用示例详解的详细内容,更多关于socket编程bind函数的资料请关注软件开发网其它相关文章!



示例 函数 bind socket

需要 登录 后方可回复, 如果你还没有账号请 注册新账号