gpt4 book ai didi

c++ - 为什么在这个 UDP 客户端/服务器示例中不需要绑定(bind)客户端套接字?

转载 作者:行者123 更新时间:2023-11-28 01:35:10 24 4
gpt4 key购买 nike

在学习套接字编程时,我根据示例和阅读 Material 拼凑了以下代码。这是一个简单的 UDP 客户端/服务器示例:

客户端.cpp

#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cerrno>
#include <ctime>
#include <cstring>
#include <unistd.h>
#include <cstdlib>

int main( int argc, char* argv[] )
{
errno = 0;
int retval = 0;

// Populate server sockaddr_in.
sockaddr_in svr_si;
svr_si.sin_family = AF_INET;
const char* svr_addr = "127.0.0.3";
svr_si.sin_addr.s_addr = inet_addr( svr_addr );
svr_si.sin_port = htons( 9090 );

sockaddr_in peer_si; // Peer sockaddr_in (populated by recv())
socklen_t peer_addr_len = sizeof peer_si; // Peer sockaddr_in length

srand( time( NULL ) );

// Create socket.
int sd = socket( PF_INET, SOCK_DGRAM, 0 );

char buf[ 1024 ]; // Receive buffer
ssize_t bytes; // Sent/received bytes
ssize_t msg_len; // Length of sent message

bool cont = true;
while ( cont )
{
// Create random message of length 10 or "quit"
if ( ! ( rand() % 7 ) )
{
std::strcpy( buf, "quit" );
}
else
{
msg_len = rand() % 10;
for ( int i = 0; i < msg_len; ++i )
{
buf[ i ] = rand() % ('z' - 'A' + 1) + 'A';
}
buf[ msg_len ] = '\0';
}
std::cout << "Client sending \"" << buf << "\" to ip(" << svr_addr <<
") port(" << ntohs( svr_si.sin_port ) << ")." << std::endl;

// Send message to server.
if ( -1 == ( bytes = sendto( sd, buf, strlen( buf ), 0,
(struct sockaddr*)&svr_si,
sizeof( svr_si ) ) ) )
{
std::cout << "send() failed." << std::endl;
}

// Receive (blocking) on unbound socket; save sender address to peer_si.
bytes = recvfrom( sd, buf, sizeof buf - 1, 0, (sockaddr*)&peer_si,
&peer_addr_len );
if ( bytes >= 0 )
{
buf[ bytes ] = '\0';

std::cout << "Client received " << bytes << " bytes from addr(" <<
inet_ntoa( peer_si.sin_addr ) << ") port(" << peer_si.sin_port <<
"): [" << buf << "]" << std::endl;
std::cout << "Server acked." << std::endl;
if ( ! std::strcmp( buf, "quit" ) )
{
std::cout << "Client quitting." << std::endl;
cont = false;
}
}
else
{
std::cout << "recvfrom() failed: " << errno << "(" << strerror( errno )
<< ")." << std::endl;
retval = 1;
cont = false;
}
}

if ( -1 != sd )
{
close( sd );
}

return retval;
}

server.cpp

#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cerrno>
#include <cstring>
#include <unistd.h>

int main( int argc, char* argv[] )
{
errno = 0;
int retval = 0;

// Create a socket.
int sd = socket( PF_INET, SOCK_DGRAM, 0 );

// Initialize a sockaddr_in with this' (the server's) address.
sockaddr_in si;
si.sin_family = AF_INET;
si.sin_addr.s_addr = inet_addr( "127.0.0.3" );
si.sin_port = htons( 9090 );

sockaddr_in peer_si; // Peer sockaddr_in
socklen_t peer_addr_len = sizeof peer_si; // Peer sockaddr length
memset( &peer_si, 0, peer_addr_len );

// Bind address to socket.
if ( ! bind( sd, (sockaddr*)&si, sizeof si ) )
{
char buf[ 1024 ]; // Receive buffer
ssize_t bytes; // Bytes received
bool cont = true;

while ( cont )
{
// Receive (blocking) on bound socket.
bytes = recvfrom( sd, buf, sizeof buf - 1, 0, (sockaddr*)&peer_si,
&peer_addr_len );
if ( bytes >= 0 )
{
buf[ bytes ] = '\0';

std::cout << "Server received " << bytes << " bytes from addr(" <<
inet_ntoa( peer_si.sin_addr ) << ") port(" <<
peer_si.sin_port << ") family(" << peer_si.sin_family <<
"): [" << buf << "]" << std::endl;
std::cout << "Server acking." << std::endl;

if ( ! std::strcmp( buf, "quit" ) )
{
std::cout << "Server quitting." << std::endl;
cont = false;
}
else
{
// Send "ack" back to whatever was read into peer_si.
bytes = sendto( sd, "ack", 3, 0, (struct sockaddr*)&peer_si,
peer_addr_len );
if ( 3 != bytes )
{
std::cout << "sendto() failed: " << errno << "(" <<
strerror( errno ) << ")" << std::endl;
retval = 1;
cont = false;
}
}
}
else
{
std::cout << "recvfrom() failed: " << errno << "(" << strerror( errno )
<< ")." << std::endl;
retval = 1;
cont = false;
}
}
}
else
{
std::cout << "bind() failed: " << errno << "(" << strerror( errno ) << ")."
<< std::endl;
retval = 1;
}

if ( -1 != sd )
{
if ( 0 != peer_si.sin_addr.s_addr )
{
sendto( sd, "quit", 4, 0, (struct sockaddr*)&peer_si, peer_addr_len );
}
close( sd );
}

return retval;
}

编译执行可以按如下方式进行:

>g++ --version
g++ (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

>g++ -g client.cpp -o client
>g++ -g server.cpp -o server

>./server &
[1] 19106
>./client
Client sending "vw" to ip(127.0.0.3) port(9090).
Server received 2 bytes from addr(127.0.0.1) port(12004) family(2): [vw]
Server acking.
Client received 3 bytes from addr(127.0.0.3) port(33315): [ack]
Server acked.
Client sending "M" to ip(127.0.0.3) port(9090).
Server received 1 bytes from addr(127.0.0.1) port(12004) family(2): [M]
Server acking.
Client received 3 bytes from addr(127.0.0.3) port(33315): [ack]
Server acked.
Client sending "quit" to ip(127.0.0.3) port(9090).
Server received 4 bytes from addr(127.0.0.1) port(12004) family(2): [quit]
Server acking.
Server quitting.
Client received 4 bytes from addr(127.0.0.3) port(33315): [quit]
Server acked.
Client quitting.
[1]+ Done ./server

我的问题:

似乎不需要 bind() 客户端上的套接字 - 为什么?您会在 client.cpp 中注意到,我所做的只是在发送消息之前创建套接字。服务器似乎可以很好地接收消息,而且能够将消息发送回它从 recvfrom() 填充的地址获得的地址。

客户端套接字的 bind() 看似不必要与自动将套接字绑定(bind)到 INADDR_ANY 有什么关系吗?如果是这样,为什么客户端套接字绑定(bind)的结果 IP 地址恰好是 127.0.0.1?它可能是一个不同的“可用”IP,例如127.0.0.2?

最佳答案

第一次发送时,如有必要,会自动绑定(bind)。也许先发送或接收,不确定。

Why does the resulting IP address that the client's socket is bound to happen to be 127.0.0.1

因为您要发送到本地地址。它将根据到达目的地的静态 IP 路由表选择正确的本地 IP 地址。

Could it ever be a different "available" IP, e.g. 127.0.0.2

帮不上忙,抱歉。

关于c++ - 为什么在这个 UDP 客户端/服务器示例中不需要绑定(bind)客户端套接字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49641312/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com