[英]Choosing socket output interface: SO_BINDTODEVICE vs bind before connect
[英]socket connect() vs bind()
connect()
和bind()
系统都调用将套接字文件描述符“关联”到一个地址(通常是ip /端口组合)。 他们的原型是:
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
和
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
2个通话之间的确切区别是什么? 什么时候应该使用connect()
和何时bind()
?
具体来说,在一些示例服务器客户端代码中,发现客户端正在使用connect()
而服务器正在使用bind()
调用。 原因对我来说还不是很清楚。
为了更好地理解,让我们找出确切的绑定和连接出现在哪里,
Sourav明确指出,除了定位两个电话外,
bind()将套接字与其本地地址相关联(这就是服务器端绑定的原因,以便客户端可以使用该地址连接到服务器。)connect()用于连接到远程[server]地址,这就是客户端的原因,使用connect [读取为:连接到服务器]。
由于特定的角色和相应的实现,我们不能互换使用它们(即使我们在同一台计算机上有客户端/服务器)。
我将进一步建议将这些调用与TCP / IP握手相关联。
因此,谁将在此处发送SYN,它将是connect()。 而bind()用于定义通信端点。
希望这可以帮助!!
一个衬里: bind()
到自己的地址, connect()
到远程地址。
从bind()
手册页引用
bind()将addr指定的地址分配给文件描述符sockfd所引用的套接字。 addrlen指定addr指向的地址结构的大小(以字节为单位)。 传统上,此操作称为“为套接字分配名称”。
并且,对于connect()
也是一样
connect()系统调用将文件描述符sockfd引用的套接字连接到addr指定的地址。
澄清,
bind()
将套接字与其本地地址相关联(这就是服务器端bind
s的原因,以便客户端可以使用该地址连接到服务器。) connect()
用于连接到远程[服务器]地址,这就是为什么在客户端使用connect [读取为:连接到服务器]。 绑定告诉正在运行的进程声明一个端口。 也就是说,它应该将自己绑定到端口80并监听传入的请求。 使用bind,您的进程将成为服务器。 使用connect时,您告诉进程连接到已在使用的端口。 您的流程成为客户。 区别很重要:bind需要一个未使用的端口(以便它可以声明它并成为服务器),而connect需要一个已经在使用的端口(以便它可以连接到该端口并与服务器通信)。
摘自Wikipedia http://en.wikipedia.org/wiki/Berkeley_sockets#bind.28.29
connect():
connect()系统调用将套接字(由其文件描述符标识)连接到由该主机在参数列表中的地址指定的远程主机。
某些类型的套接字是无连接的,最常见的是用户数据报协议套接字。 对于这些套接字,connect具有特殊含义:用于发送和接收数据的默认目标被设置为给定地址,从而允许在无连接套接字上使用诸如send()和recv()之类的功能。
connect()返回代表错误代码的整数:0代表成功,而-1代表错误。
bind():
bind()将套接字分配给一个地址。 使用socket()创建套接字时,只会为其分配协议族,而不会分配地址。 在套接字可以接受到其他主机的连接之前,必须通过bind()系统调用执行与地址的这种关联。 bind()采用三个参数:
sockfd,表示要在其上进行绑定的套接字的描述符。 my_addr,一个指向sockaddr结构的指针,该结构代表要绑定的地址。 addrlen,一个socklen_t字段,指定sockaddr结构的大小。 Bind()成功返回0,如果发生错误则返回-1。
示例:1.)使用Connect
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
int main(){
int clientSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
socklen_t addr_size;
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
clientSocket = socket(PF_INET, SOCK_STREAM, 0);
/*---- Configure settings of the server address struct ----*/
/* Address family = Internet */
serverAddr.sin_family = AF_INET;
/* Set port number, using htons function to use proper byte order */
serverAddr.sin_port = htons(7891);
/* Set the IP address to desired host to connect to */
serverAddr.sin_addr.s_addr = inet_addr("192.168.1.17");
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Connect the socket to the server using the address struct ----*/
addr_size = sizeof serverAddr;
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
/*---- Read the message from the server into the buffer ----*/
recv(clientSocket, buffer, 1024, 0);
/*---- Print the received message ----*/
printf("Data received: %s",buffer);
return 0;
}
2.)绑定示例:
int main()
{
struct sockaddr_in source, destination = {}; //two sockets declared as previously
int sock = 0;
int datalen = 0;
int pkt = 0;
uint8_t *send_buffer, *recv_buffer;
struct sockaddr_storage fromAddr; // same as the previous entity struct sockaddr_storage serverStorage;
unsigned int addrlen; //in the previous example socklen_t addr_size;
struct timeval tv;
tv.tv_sec = 3; /* 3 Seconds Time-out */
tv.tv_usec = 0;
/* creating the socket */
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
printf("Failed to create socket\n");
/*set the socket options*/
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));
/*Inititalize source to zero*/
memset(&source, 0, sizeof(source)); //source is an instance of sockaddr_in. Initialization to zero
/*Inititalize destinaton to zero*/
memset(&destination, 0, sizeof(destination));
/*---- Configure settings of the source address struct, WHERE THE PACKET IS COMING FROM ----*/
/* Address family = Internet */
source.sin_family = AF_INET;
/* Set IP address to localhost */
source.sin_addr.s_addr = INADDR_ANY; //INADDR_ANY = 0.0.0.0
/* Set port number, using htons function to use proper byte order */
source.sin_port = htons(7005);
/* Set all bits of the padding field to 0 */
memset(source.sin_zero, '\0', sizeof source.sin_zero); //optional
/*bind socket to the source WHERE THE PACKET IS COMING FROM*/
if (bind(sock, (struct sockaddr *) &source, sizeof(source)) < 0)
printf("Failed to bind socket");
/* setting the destination, i.e our OWN IP ADDRESS AND PORT */
destination.sin_family = AF_INET;
destination.sin_addr.s_addr = inet_addr("127.0.0.1");
destination.sin_port = htons(7005);
//Creating a Buffer;
send_buffer=(uint8_t *) malloc(350);
recv_buffer=(uint8_t *) malloc(250);
addrlen=sizeof(fromAddr);
memset((void *) recv_buffer, 0, 250);
memset((void *) send_buffer, 0, 350);
sendto(sock, send_buffer, 20, 0,(struct sockaddr *) &destination, sizeof(destination));
pkt=recvfrom(sock, recv_buffer, 98,0,(struct sockaddr *)&destination, &addrlen);
if(pkt > 0)
printf("%u bytes received\n", pkt);
}
我希望可以澄清差异
请注意,您声明的套接字类型将取决于您的要求,这非常重要
我认为,如果connect()
和listen()
视为对等物,而不是connect()
和bind()
,则对您的理解会有所帮助。 这样做的原因是您可以在其中一个之前调用或忽略bind()
,尽管在connect()
之前调用它,或者在listen()
之前不调用它很少是一个好主意。
如果有助于从服务器和客户端的角度进行思考,那就是listen()
是前者的标志,而connect()
是后者的标志。 bind()
可以找到-或找不到。
如果我们假设服务器和客户端位于不同的计算机上,则更容易理解各种功能。
bind()
在本地起作用,也就是说,它将被调用的机器上的连接结束绑定到所请求的地址,并将所请求的端口分配给您。 不管该计算机是客户端还是服务器,它都会这样做。 connect()
启动到服务器的连接,也就是说,它从客户端连接到服务器上请求的地址和端口。 该服务器几乎肯定会在listen()
bind()
之前调用bind()
,以便您可以使用connect()
知道连接到哪个地址和端口。
如果不调用bind()
,则在调用connect()
(客户端)或listen()
(服务器)时,将为您隐式分配端口和地址并将其绑定到本地计算机上。 但是,这是两者的副作用,而不是目的。 以这种方式分配的端口是短暂的。
这里的重要一点是,不需要绑定客户端,因为客户端连接到服务器,因此即使您使用的是临时端口,服务器也将知道客户端的地址和端口,而不是绑定到特定的端口。 另一方面,尽管服务器可以在不调用bind()
情况下调用listen()
,但是在这种情况下,它们将需要发现分配的临时端口,并将其传达给它要连接的任何客户端。
我假设您提到connect()
您对TCP感兴趣,但这也会延续到UDP,在第一个sendto()
(UDP无连接的情况下bind()
之前,不调用bind()
)也会导致端口和地址变为隐式分配和绑定。 如果没有绑定,则不能调用的一个函数是recvfrom()
,它将返回一个错误,因为如果没有分配的端口和绑定的地址,则无法接收任何内容(或者太多,取决于您对绑定的理解)。
太长; 不读:区别在于是否设置了源(本地)或目标地址/端口。 简而言之, bind()
设置源, connect()
设置目标。 不论TCP还是UDP。
bind()
bind()
设置套接字的本地(源)地址。 这是接收数据包的地址。 套接字发送的数据包将其作为源地址,因此另一台主机将知道将其数据包发回何处。
如果不需要接收,则套接字源地址无效。 像TCP这样的协议需要启用接收才能正确发送,因为目标主机在一个或多个数据包到达时会发回一个确认(即确认)。
connect()
connect()
触发TCP代码尝试建立到另一端的连接。 connect()
仅在未指定地址的情况下,将默认地址设置为将数据包发送到的默认地址。 当不使用connect()
,必须使用包含目标地址的sendto()
或sendmsg()
。 当调用connect()
或send函数,并且没有地址绑定时,Linux会自动将套接字绑定到随机端口。 有关技术细节,请查看Linux内核源代码中的inet_autobind()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.