将数据发送到多个客户端 UDP 时不支持地址族
Address family not supported when sending data to multiple clients UDP
我目前正在用linux编写一个程序,其中:
-
客户端向服务器发送"密码">
-
服务器等待n个人发送密码并记录发件人地址
-
收到 N 条消息后,将向发件人发送启动消息。
问题是当我尝试将"开始"发送回客户端时,我收到非法查找错误(发送中的错误:非法查找(。并且只有第一个客户端收到启动消息(clientaddrs[0]
(
注意:经过 30 分钟的测试,错误现在变为:协议不支持地址系列。(代码中绝对没有任何变化(
这是我的代码(我粘贴了一个最小的可重现示例(
要重现此问题:
-
使用参数运行服务器代码:8080
-
在提示符下输入 2
-
在两个不同的参数上运行客户端代码:127.0.0.1 8080
-
选择两个不同的密码,并在客户端提示时输入它们
服务器代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <chrono>
#include <errno.h>
#include <ifaddrs.h>
#define TO_CLI_BUF_SIZE 32
#define FROM_CLI_BUF_SIZE 8
void printAddr(){ // for printing my ip
struct ifaddrs * ifAddrStruct=NULL;
struct ifaddrs * ifa=NULL;
void * tmpAddrPtr=NULL;
getifaddrs(&ifAddrStruct);
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr) {
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
// is a valid IP4 Address
tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
char addressBuffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
printf("%s IP Address %sn", ifa->ifa_name, addressBuffer);
} else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6
// is a valid IP6 Address
tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
char addressBuffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
printf("%s IP Address %sn", ifa->ifa_name, addressBuffer);
}
}
if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
}
int main(int argc, char ** argv){
//seed rand
srand(time(NULL));
int sockfd; // socket
int port; // my port to listen on
struct sockaddr_in serveraddr; // server's address
struct sockaddr_in clientaddrs[4];
socklen_t clientLens[4];
int currentAddrMax = 0;
struct hostent * hostp; //host info
char * hostaddrp; // host adddr string
char toClientBuf[TO_CLI_BUF_SIZE];
char fromClientBuf[FROM_CLI_BUF_SIZE];
if(argc != 2){
perror("usage: file <port>");
exit(1);
}
port = atoi(argv[1]);
// create socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd<0){
perror("ERROR: opening socket.");
exit(1);
}
//int option = 1;
//setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&option, sizeof(int));
//internet stuff
bzero((char*) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)port);
if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){
perror("ERROR on bind");
exit(1);
}
int playerKeys[4];
int playerJoined[4];
printf("(you can enter 1,2,3 or 4)n");
printf("Enter amount of players: n");
int amountPlayers = 0;
scanf("%d",&amountPlayers);
// hacky way to clear screen
printf(" 33[H 33[J");
printAddr();
printf("PORT: %dn", port);
printf("player| key| inn");
for(int i = 0; i < 4; i++){
bool keyExists = true;
while (keyExists == true ){
playerKeys[i] = rand()%10000;
keyExists = false;
for(int j = 0; j < i; j++){
if(playerKeys[i] == playerKeys[j]){
keyExists = true;
}
}
}
printf("%d |%04d|",i+1, playerKeys[i]);
if(playerJoined[i] == 1){
printf(" on");
}else{
printf(" xn");
}
fflush(stdin);
}
for(int i = 0; i < amountPlayers;i++){
bzero(fromClientBuf, FROM_CLI_BUF_SIZE);
int n = recvfrom(sockfd, fromClientBuf,FROM_CLI_BUF_SIZE, 0, (struct sockaddr*) &clientaddrs[currentAddrMax], &(clientLens[currentAddrMax]));
//TODO store senders
if(n>0){
int key = (fromClientBuf[0]-'0')*1000; //TODO change the way keys are extracted.
key += (fromClientBuf[1]-'0')*100;
key += (fromClientBuf[2]-'0')*10;
key += (fromClientBuf[3]-'0');
for (int i = 0; i < 4; i++){
if(playerKeys[i] == key && playerJoined[i] == 0){
playerJoined[i] = 1;
currentAddrMax++;
}
}
printf(" 33[H 33[J");
printAddr();
printf("PORT: %dn", port);
printf("player| key| inn");
for(int i = 0; i < 4; i++){
printf("%d |%04d|",i+1, playerKeys[i]);
if(playerJoined[i] == 1){
printf(" on");
}else{
printf(" xn");
}
}
// decode key
}
}
//TODO finished waiting for all senders. send them start signal
//MAY BE USEFULL:n = sendto(sockfd, toClientBuf, strlen(toClientBuf), 0, (struct sockaddr *) &clientaddr, clientlen);
strcpy(toClientBuf, "start");
for(int j = 0; j < currentAddrMax; j++){
int n = sendto(sockfd, toClientBuf, strlen(toClientBuf), 0, (struct sockaddr *) &clientaddrs[j], (clientLens[j]));
if(n < 0) {
perror("ERROR in sendto");
printf("%dn",j);
exit(1);
}
}
// wait for connections
//main loop
//set some options
struct timeval read_timeout;
read_timeout.tv_sec = 0;
read_timeout.tv_usec = 100;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,&read_timeout,sizeof(read_timeout)) < 0) {
perror("Error with options");
}
printf("start loopn");
return 0;
}
客户端代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define FROM_SER_BUF_SIZE 32
#define TO_SER_BUF_SIZE 8
int main(int argc, char **argv){
int sockfd, portno, n;
socklen_t serverlen;
struct sockaddr_in serveraddr;
struct hostent *server;
char *hostname;
char toServerBuf[TO_SER_BUF_SIZE];
char fromServerBuf[FROM_SER_BUF_SIZE];
if (argc != 3) {
perror("usage: filename <hostname> <port>n");
exit(0);
}
hostname = argv[1];
portno = atoi(argv[2]);
// create socket
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("ERROR: opening socketsn");
exit(0);
}
// get host
server = gethostbyname(hostname);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host as %sn", hostname);
exit(0);
}
// build server's internet address
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serveraddr.sin_addr.s_addr, server->h_length);
serveraddr.sin_port = htons(portno);
bzero(toServerBuf, TO_SER_BUF_SIZE);
int key = 0;
printf("Please enter your key: ");
scanf("%d",&key);
if(key > 9999 || key < 0){
printf("INVALID KEYn");
exit(1);
}
toServerBuf[0] = key/1000 + '0';
toServerBuf[1] = (key%1000)/100 + '0';
toServerBuf[2] = (key%100)/10 +'0';
toServerBuf[3] = key%10 + '0';
serverlen = sizeof(serveraddr);
n = sendto(sockfd, toServerBuf, strlen(toServerBuf), 0, ( struct sockaddr *) &serveraddr, serverlen);
if (n < 0){
perror("ERROR: sendton");
exit(0);
}
//TODO wait for server to get send start signal
bzero(fromServerBuf, FROM_SER_BUF_SIZE);
n = recvfrom(sockfd, fromServerBuf, FROM_SER_BUF_SIZE, 0,( struct sockaddr *) &serveraddr, &serverlen);
printf("wow we got here");
return 0;
}
事实证明,这是 g++ 的问题。不知道为什么 g++ 不起作用,但是,一旦我切换到 clang 我所有的错误都消失了。但是,clang++也不起作用。
编辑:valgrind发现的clientaddr长度有问题。结果在客户端 legnths 的数组中(对于我的例子(,我们必须首先用
clientLens[currentAddrMax] = sizeof(clientaddrs[currentAddrMax]);
正如 Bodo 所提到的,我们必须始终初始化客户端长度,否则会出现未指定的行为。
相关文章:
- 为什么istream不支持右值提取
- 错误:(-210:不支持的格式或格式组合)功能'create'中的硬件视频解码器不支持视频源
- Casablanca/cpprestsdk listener.support接受函数,但不支持方法
- 为什么C++不支持对未初始化变量进行智能分析?
- 在 c++ 中连接字符串和整数,以便在 C++ 11 不支持计算机的情况下读取多个文件
- 在 Ubuntu 18.04 上编译 GLSL 着色器时"不支持 GLSL 3.30"?
- 为什么联机C++ IDE 不支持"graphics.h"头文件?
- Clang编译器不支持aarch64-apple-darwin上的-fxray-instrument
- 为什么我的 clang 格式不支持 PPDirectiveIndentStyle 选项?
- 为什么某些 STL 容器(堆栈、队列、优先级队列)不支持迭代器?
- 为什么不支持 Xcode 1.5?
- C++20 从括号中的值列表初始化聚合,不支持内部数组
- 为什么结构化绑定不支持可变数组?
- 您选择的 CPU 不支持 x86-64 指令集
- 将数据发送到多个客户端 UDP 时不支持地址族
- 缺少类型说明符 - 假定为 int.注意 c++ 不支持 default-int
- 瓦尔格林德"不支持arch_prctl选项"
- 错误:C4430:缺少类型说明符-假定为int.注意:C++不支持default-int
- 不支持 GLSL 330 内核
- 为什么Visual Studio 2019不支持用于减少Openmp的关键字"max"?