bind函数详解
看看man手冊(cè):
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)函數(shù)原型:
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);成功返回0,出錯(cuò)返回-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) */}服務(wù)器端和客戶端程序的顯著區(qū)別在于客戶端程序不需要調(diào)用bind函數(shù),bind函數(shù)的作用是將套接字綁定一個(gè)IP地址和端口號(hào),因?yàn)檫@兩個(gè)元素可以在網(wǎng)絡(luò)環(huán)境中唯一地址表示一個(gè)進(jìn)程。如果套接字沒有使用bind函數(shù)綁定地址和端口,那么調(diào)用listen函數(shù)和connect函數(shù)的時(shí)候內(nèi)核會(huì)自動(dòng)為套接字綁定。由此可知,如果沒有使用bind函數(shù),調(diào)用listen函數(shù)和connect函數(shù)的時(shí)候內(nèi)核會(huì)自動(dòng)為套接字綁定。看起來好像bind函數(shù)是多余的,但事實(shí)并不是這樣。
我們先來看看listen函數(shù)和connect是怎么綁定套接字的,connect函數(shù)綁定套接字的時(shí)候使用的是一個(gè)設(shè)置好的地址結(jié)構(gòu)(sockaddr_in)作為參數(shù),結(jié)構(gòu)中指定了服務(wù)器的地址和需要通信的端口號(hào)。但是listen函數(shù)沒有這個(gè)參數(shù),多以listen函數(shù)不能夠使用設(shè)置好的地址結(jié)構(gòu),只能由系統(tǒng)設(shè)置IP地址和端口號(hào)。也就是說在服務(wù)器端,如果不使用bind函數(shù)的話,創(chuàng)建套接字時(shí)使用的是當(dāng)前系統(tǒng)中空閑端口的套接字。
這樣的話,服務(wù)器端的程序不關(guān)心客戶端的IP地址,也就說是對(duì)應(yīng)的端口號(hào)是內(nèi)核臨時(shí)指派的一個(gè)端口,是隨機(jī)的,每次執(zhí)行服務(wù)器程序的時(shí)候,使用的都是不同的端口。但是在客戶端是需要指定通信的服務(wù)器的端口的,如果不使用bind函數(shù),每次的端口是隨機(jī)的話,那么每次重啟服務(wù)程序之后都要對(duì)客戶端的程序進(jìn)行調(diào)整,這樣做不僅不合理,而且工作量很大,因此在服務(wù)器端bind函數(shù)作用非常重要。
使用bind函數(shù)的歷程:
總結(jié)
- 上一篇: 作者:宾军志(1976-),男,御数坊(
- 下一篇: 作者: 李国杰,中国工程院院士。现任中