fra*_*an1 1 c sockets udp bind getaddrinfo
使用BJ的talker.c代码作为模板: http://beej.us/guide/bgnet/examples/talker.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define SERVERPORT "4950" // the port users will be connecting to
int main(int argc, char *argv[])
{
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
int numbytes;
struct sockaddr_storage their_addr;
socklen_t addr_len;
addr_len = sizeof their_addr;
if (argc != 3) {
fprintf(stderr,"usage: talker hostname message\n");
exit(1);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "talker: failed to create socket\n");
return 2;
}
if ((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0,
p->ai_addr, p->ai_addrlen)) == -1) {
perror("talker: sendto");
exit(1);
}
freeaddrinfo(servinfo);
printf("talker: sent %d bytes to %s\n", numbytes, argv[1]);
//============== Added Code for recvfrom() (pseudocode-ish) =============
if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN , 0, (struct sockaddr *)&their_addr, &addr_len)) == -1)
{
close(sockfd);
perror("talker: recvfrom");
exit(1);
}
close(sockfd);
printf("Got packet\n");
//============== End Added Code for recvfrom() =============
close(sockfd);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我有一个要求,即与服务器通信的客户端 UDP 进程必须使用固定的已知source端口号。在本例中,假设它是SERVERPORT(4950)。然后服务器响应该端口号。是的,这是不寻常的,因为大多数服务器都会响应系统分配给发送者的临时端口号。
使用 发送数据包后sendto(),我使用 监听响应recvfrom()。这是我在上面的示例中添加的(伪)代码。
我所有的在线搜索都指向使用,bind()但该代码通常位于服务器端。我还没有找到使用现代方法在客户端进行绑定的方法getaddrinfo()。我尝试在设置bind()后添加一个 right,socket()但这不起作用,因为p它是一个服务器端结构(源自使用服务器 IP 地址的提示结构),并且出现绑定错误:
Error 99 (Cannot assign requested address)
添加代码:
bind(sockfd, p->ai_addr, p->ai_addrlen)
我想以一种同时适用于 IPv4 和 IPv6 的方式来完成此操作。
我见过其他示例,其中本地/源 sockaddr_in 结构填充了客户端信息并在绑定中使用,但这些是特定于 IPv4 或 IPv6 的。
有人可以告诉我如何使用固定源talker.c端口号正确地将代码更新到sendto()UDPrecvfrom()服务器吗?假设服务器是不可变的。
然后服务器响应该端口号。是的,这很不寻常
这并没有什么不寻常的。这就是大多数 UDP 服务器的工作方式。他们总是响应发送者的端口。他们不知道该端口是固定的还是临时的,这由发送者决定。除非特定协议规定将响应发送到不同的端口,但这种情况并不常见。
我所有的在线搜索都指向使用
bind()
正确,这就是您在这种情况下所需要的。
但该代码通常位于服务器端。
没有什么可以阻止客户使用bind().
我还没有找到使用现代方法在客户端进行绑定的方法
getaddrinfo()。
它与服务器端完全相同,除了您必须绑定到特定的 IP 地址,您不能绑定到服务器套接字0.0.0.0或::0像使用服务器套接字一样。
我尝试在设置
bind()后添加一个socket(),但这不起作用
是的,它确实。问题是您使用相同的IP 地址进行绑定和发送,这是行不通的。您需要绑定到CLIENT的IP地址,然后发送到SERVER的IP地址。
因为
p是服务器端结构(源自hints使用服务器IP地址的结构)
你滥用了p。您无法将bind()客户端套接字连接到服务器的 IP 地址(您需要使用connect()它来代替)。您需要bind()一个连接到客户端计算机本地 IP 地址的客户端套接字。就像您必须将bind()服务器套接字连接到服务器计算机本地的 IP 地址一样。
请记住,一个套接字与一对 IP 地址相关联。 bind()建立套接字的本地IP 地址。 connect()建立套接字的远程IP 地址。
我想以一种同时适用于 IPv4 和 IPv6 的方式来完成此操作。
您无法为这两种协议创建单个客户端套接字。每个协议都需要单独的套接字(在服务器端,如果您的平台支持双栈套接字,则可以为这两个协议创建单个套接字)。
我见过其他示例,其中本地/源
sockaddr_in结构填充有客户端信息并在绑定中使用,但这些示例是 IPv4 或 IPv6 特定的。
是的,因为您将使用 IPv4 或 IPv6 发送数据包,所以您不能同时使用这两种协议发送数据包(不过,双栈套接字可以从任一协议接收数据包)。
有人可以告诉我如何使用固定源端口号正确更新
talker.c代码sendto()和UDP 服务器吗?recvfrom()假设服务器是不可变的
尝试这样的事情:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdbool.h>
#define LOCALPORT "4950" // the port users will be sending from
#define SERVERPORT "4950" // the port users will be connecting to
#define MAXBUFLEN 65535
int main(int argc, char *argv[])
{
int sockfd;
struct addrinfo hints, *myinfo, *servinfo, *pserv, *plocal;
int rv;
int numbytes;
char buf[MAXBUFLEN];
char ipstr[INET6_ADDRSTRLEN];
fd_set readfds;
struct timeval tv;
bool stop = false;
if (argc < 3) {
fprintf(stderr, "usage: talker destaddr message [localaddr]\n");
return 1;
}
// get all of the server addresses
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 2;
}
// loop through all the server addresses
for(pserv = servinfo; (pserv != NULL) && (!stop); pserv = pserv->ai_next) {
memset(ipstr, 0, sizeof(ipstr));
switch (pserv->ai_family)
{
case AF_INET:
inet_ntop(AF_INET, &(((struct sockaddr_in*)pserv->ai_addr)->sin_addr), ipstr, INET_ADDRSTRLEN);
break;
case AF_INET6:
inet_ntop(AF_INET6, &(((struct sockaddr_in6*)pserv->ai_addr)->sin6_addr), ipstr, INET6_ADDRSTRLEN);
break;
}
printf("talker: trying to send message to %s\n", ipstr);
// get all of the matching local addresses
memset(&hints, 0, sizeof hints);
hints.ai_family = pserv->ai_family;
hints.ai_socktype = pserv->ai_socktype;
hints.ai_protocol = pserv->ai_protocol;
if ((rv = getaddrinfo(argc > 3 ? argv[3] : NULL, LOCALPORT, &hints, &myinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
continue;
}
// loop through all the local addresses, sending the
// message from each one until a reply is received
for(plocal = myinfo; (plocal != NULL) && (!stop); plocal = plocal->ai_next) {
if ((sockfd = socket(plocal->ai_family, plocal->ai_socktype, plocal->ai_protocol)) == -1) {
perror("socket");
continue;
}
memset(ipstr, 0, sizeof(ipstr));
switch (plocal->ai_family)
{
case AF_INET:
inet_ntop(AF_INET, &(((struct sockaddr_in*)plocal->ai_addr)->sin_addr), ipstr, INET_ADDRSTRLEN);
break;
case AF_INET6:
inet_ntop(AF_INET6, &(((struct sockaddr_in6*)plocal->ai_addr)->sin6_addr), ipstr, INET6_ADDRSTRLEN);
break;
}
printf("talker: binding to %s\n", ipstr);
if (bind(sockfd, plocal->ai_addr, plocal->ai_addrlen) == -1) {
perror("bind");
close(sockfd);
continue;
}
// make sure this server address is the only one we talk to
if (connect(sockfd, pserv->ai_addr, pserv->ai_addrlen) == -1) {
perror("connect");
close(sockfd);
continue;
}
if ((numbytes = send(sockfd, argv[2], strlen(argv[2]), 0)) == -1) {
perror("send");
close(sockfd);
continue;
}
printf("talker: sent %d bytes\n", numbytes);
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
tv.tv_sec = 5;
tv.tv_usec = 0;
rv = select(sockfd+1, &readfds, NULL, NULL, &tv);
if (rv == -1)
{
perror("select");
close(sockfd);
continue;
}
if (rv == 0)
{
printf("talker: no reply for 5 seconds\n");
close(sockfd);
continue;
}
if ((numbytes = recv(sockfd, buf, MAXBUFLEN, 0)) == -1)
{
perror("recv");
close(sockfd);
continue;
}
printf("talker: received %d bytes\n", numbytes);
close(sockfd);
stop = true;
break;
}
freeaddrinfo(myinfo);
}
freeaddrinfo(servinfo);
close(sockfd);
if (!stop) {
fprintf(stderr, "talker: failed to communicate with server\n");
return 3;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5223 次 |
| 最近记录: |