當前位置:
首頁 >
bind函数详解
發布時間:2025/3/15
28
豆豆
看看man手冊:
BIND(2) Linux Programmer's Manual BIND(2)NAMEbind - bind a name to a socketSYNOPSIS#include <sys/types.h> /* See NOTES */#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);DESCRIPTIONWhen a socket is created with socket(2), it exists in a name space(address family) but has no address assigned to it. bind() assigns theaddress specified by addr to the socket referred to by the filedescriptor sockfd. addrlen specifies the size, in bytes, of theaddress structure pointed to by addr. Traditionally, this operation iscalled “assigning a name to a socket”.It is normally necessary to assign a local address using bind() beforea SOCK_STREAM socket may receive connections (see accept(2)).The rules used in name binding vary between address families. Consultthe manual entries in Section 7 for detailed information. For AF_INETsee ip(7), for AF_INET6 see ipv6(7), for AF_UNIX see unix(7), forAF_APPLETALK see ddp(7), for AF_PACKET see packet(7), for AF_X25 seex25(7) and for AF_NETLINK see netlink(7).The actual structure passed for the addr argument will depend on theaddress family. The sockaddr structure is defined as something like:struct sockaddr {sa_family_t sa_family;char sa_data[14];}The only purpose of this structure is to cast the structure pointerpassed in addr in order to avoid compiler warnings. See EXAMPLE below.RETURN VALUEOn success, zero is returned. On error, -1 is returned, and errno isset appropriately.ERRORSEACCES The address is protected, and the user is not the superuser.EADDRINUSEThe given address is already in use.EADDRINUSE(Internet domain sockets) The port number was specified as zeroin the socket address structure, but, upon attempting to bind toan ephemeral port, it was determined that all port numbers inthe ephemeral port range are currently in use. See the discus‐sion of /proc/sys/net/ipv4/ip_local_port_range ip(7).EBADF sockfd is not a valid descriptor.EINVAL The socket is already bound to an address.EINVAL addrlen is wrong, or addr is not a valid address for thissocket's domain.ENOTSOCKThe file descriptor sockfd does not refer to a socket.The following errors are specific to UNIX domain (AF_UNIX) sockets:EACCES Search permission is denied on a component of the path prefix.(See also path_resolution(7).)EADDRNOTAVAILA nonexistent interface was requested or the requested addresswas not local.EFAULT addr points outside the user's accessible address space.ELOOP Too many symbolic links were encountered in resolving addr.ENAMETOOLONGaddr is too long.ENOENT The file does not exist.ENOMEM Insufficient kernel memory was available.ENOTDIRA component of the path prefix is not a directory.EROFS The socket inode would reside on a read-only filesystem.CONFORMING TOPOSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD (bind() first appeared in4.2BSD).NOTESPOSIX.1 does not require the inclusion of <sys/types.h>, and thisheader file is not required on Linux. However, some historical (BSD)implementations required this header file, and portable applicationsare probably wise to include it.The third argument of bind() is in reality an int (and this is what 4.xBSD and libc4 and libc5 have). Some POSIX confusion resulted in thepresent socklen_t, also used by glibc. See also accept(2).BUGSThe transparent proxy options are not described.EXAMPLEAn example of the use of bind() with Internet domain sockets can befound in getaddrinfo(3).The following example shows how to bind a stream socket in the UNIX(AF_UNIX) domain, and accept connections:#include <sys/socket.h>#include <sys/un.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#define MY_SOCK_PATH "/somepath"#define LISTEN_BACKLOG 50#define handle_error(msg) \do { perror(msg); exit(EXIT_FAILURE); } while (0)intmain(int argc, char *argv[]){int sfd, cfd;struct sockaddr_un my_addr, peer_addr;socklen_t peer_addr_size;sfd = socket(AF_UNIX, SOCK_STREAM, 0);if (sfd == -1)handle_error("socket");memset(&my_addr, 0, sizeof(struct sockaddr_un));/* Clear structure */my_addr.sun_family = AF_UNIX;strncpy(my_addr.sun_path, MY_SOCK_PATH,sizeof(my_addr.sun_path) - 1);if (bind(sfd, (struct sockaddr *) &my_addr,sizeof(struct sockaddr_un)) == -1)handle_error("bind");if (listen(sfd, LISTEN_BACKLOG) == -1)handle_error("listen");/* Now we can accept incoming connections oneat a time using accept(2) */peer_addr_size = sizeof(struct sockaddr_un);cfd = accept(sfd, (struct sockaddr *) &peer_addr,&peer_addr_size);if (cfd == -1)handle_error("accept");/* Code to deal with incoming connection(s)... *//* When no longer required, the socket pathname, MY_SOCK_PATHshould be deleted using unlink(2) or remove(3) */}SEE ALSOaccept(2), connect(2), getsockname(2), listen(2), socket(2), getad‐drinfo(3), getifaddrs(3), ip(7), ipv6(7), path_resolution(7),socket(7), unix(7)COLOPHONThis page is part of release 4.04 of the Linux man-pages project. Adescription of the project, information about reporting bugs, and thelatest version of this page, can be found athttp://www.kernel.org/doc/man-pages/.Linux 2015-12-28 BIND(2)函數原型:
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);成功返回0,出錯返回-1man中給的例程:
#include <sys/socket.h> #include <sys/un.h> #include <stdlib.h> #include <stdio.h> #include <string.h>#define MY_SOCK_PATH "/somepath" #define LISTEN_BACKLOG 50#define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0)intmain(int argc, char *argv[]){int sfd, cfd;struct sockaddr_un my_addr, peer_addr;socklen_t peer_addr_size;sfd = socket(AF_UNIX, SOCK_STREAM, 0);if (sfd == -1)handle_error("socket");memset(&my_addr, 0, sizeof(struct sockaddr_un));/* Clear structure */my_addr.sun_family = AF_UNIX;strncpy(my_addr.sun_path, MY_SOCK_PATH,sizeof(my_addr.sun_path) - 1);if (bind(sfd, (struct sockaddr *) &my_addr,sizeof(struct sockaddr_un)) == -1)handle_error("bind");if (listen(sfd, LISTEN_BACKLOG) == -1)handle_error("listen");/* Now we can accept incoming connections oneat a time using accept(2) */peer_addr_size = sizeof(struct sockaddr_un);cfd = accept(sfd, (struct sockaddr *) &peer_addr,&peer_addr_size);if (cfd == -1)handle_error("accept");/* Code to deal with incoming connection(s)... *//* When no longer required, the socket pathname, MY_SOCK_PATHshould be deleted using unlink(2) or remove(3) */}服務器端和客戶端程序的顯著區別在于客戶端程序不需要調用bind函數,bind函數的作用是將套接字綁定一個IP地址和端口號,因為這兩個元素可以在網絡環境中唯一地址表示一個進程。如果套接字沒有使用bind函數綁定地址和端口,那么調用listen函數和connect函數的時候內核會自動為套接字綁定。由此可知,如果沒有使用bind函數,調用listen函數和connect函數的時候內核會自動為套接字綁定。看起來好像bind函數是多余的,但事實并不是這樣。
我們先來看看listen函數和connect是怎么綁定套接字的,connect函數綁定套接字的時候使用的是一個設置好的地址結構(sockaddr_in)作為參數,結構中指定了服務器的地址和需要通信的端口號。但是listen函數沒有這個參數,多以listen函數不能夠使用設置好的地址結構,只能由系統設置IP地址和端口號。也就是說在服務器端,如果不使用bind函數的話,創建套接字時使用的是當前系統中空閑端口的套接字。
這樣的話,服務器端的程序不關心客戶端的IP地址,也就說是對應的端口號是內核臨時指派的一個端口,是隨機的,每次執行服務器程序的時候,使用的都是不同的端口。但是在客戶端是需要指定通信的服務器的端口的,如果不使用bind函數,每次的端口是隨機的話,那么每次重啟服務程序之后都要對客戶端的程序進行調整,這樣做不僅不合理,而且工作量很大,因此在服務器端bind函數作用非常重要。
使用bind函數的歷程:
總結
- 上一篇: 作者:宾军志(1976-),男,御数坊(
- 下一篇: 作者: 李国杰,中国工程院院士。现任中