M1 Mac运行C客户端服务器程序遇nodename解析错误求助
问题描述
我用C语言开发了客户端与服务器程序(代码经教授审核确认无误),但在搭载M1芯片的Mac上执行以下命令时:
./client server 50000
(指定主机名server和端口50000),弹出错误提示:
名称解析错误:未提供节点名或服务名,或无法识别
我完全不清楚问题成因,以下是服务器端和客户端的C代码:
服务器端代码
#include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <errno.h> #include <netdb.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <signal.h> #define BUFSIZE 4096 const char *service = "50000"; // 处理子进程退出信号 void handler(int sign){ int status; (void)sign; while(waitpid(-1, &status, WNOHANG) > 0){ continue; } } int main(){ int cc, err, on, sd; struct addrinfo hints, *res; struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sa.sa_handler = handler; if(sigaction(SIGCHLD, &sa, NULL) == -1){ perror("sigaction调用失败"); exit(EXIT_FAILURE); } memset(&hints,0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // 此处存在错误:第一个参数不应传入stderr err = getaddrinfo(stderr,service, &hints, &res); if(err != 0){ fprintf(stderr,"getaddrinfo错误:%s\n",gai_strerror(err)); exit(EXIT_FAILURE); } sd = socket(res->ai_family, res->ai_socktype,res->ai_protocol); if(sd < 0){ perror("创建套接字失败"); exit(EXIT_FAILURE); } on = 1; if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,&on, sizeof(on)) < 0){ perror("设置套接字选项失败"); exit(EXIT_FAILURE); } cc = bind(sd, res->ai_addr, res->ai_addrlen); if(cc < 0){ perror("绑定套接字失败"); exit(EXIT_FAILURE); } cc = listen(sd, SOMAXCONN); if(cc < 0){ perror("监听套接字失败"); exit(EXIT_FAILURE); } for(;;){ int pid, ns; ns = accept(sd, NULL, NULL); if(ns < 0){ if(errno == EINTR){ continue; } perror("接受连接失败"); exit(EXIT_FAILURE); } pid = fork(); if(pid < 0){ perror("创建子进程失败"); exit(EXIT_FAILURE); }else if (pid == 0){ /*子进程*/ char year[BUFSIZE]; char number[BUFSIZE]; char type[BUFSIZE]; const char *ack = "ACK\n"; int pid_n1, pid_n2; int pipe_n1n2[2], pipe_n2f[2]; close(sd); memset(year, 0, sizeof(year)); cc = read(ns, year, sizeof(year) - 1); if(cc < 0){ perror("读取数据失败"); exit(EXIT_FAILURE); } cc = write(ns, ack, strlen(ack)); if(cc < 0){ perror("写入数据失败"); exit(EXIT_FAILURE); } memset(number,0, sizeof(number)); cc = read(ns, number, sizeof(number) - 1); if(cc < 0){ perror("读取数据失败"); exit(EXIT_FAILURE); } cc = write(ns, ack, strlen(ack)); if(cc < 0){ perror("写入数据失败"); exit(EXIT_FAILURE); } memset(type, 0, sizeof(type)); cc = read(ns, type, sizeof(type) -1); if(cc < 0){ perror("读取数据失败"); exit(EXIT_FAILURE); } cc = pipe(pipe_n1n2); if(cc < 0){ perror("创建管道失败"); exit(EXIT_FAILURE); } pid_n1 = fork(); if(pid_n1 < 0){ perror("创建子进程失败"); exit(EXIT_FAILURE); }else if (pid_n1 == 0){ /*孙子进程1*/ char db_file[BUFSIZE]; close(ns); close(pipe_n1n2[0]); close(1); dup(pipe_n1n2[1]); close(pipe_n1n2[1]); snprintf(db_file,sizeof(db_file),"/var/local/games/%s/%s.txt",year,type); execlp("sort","sort","-n","-r",db_file,NULL); exit(EXIT_FAILURE); } cc = pipe(pipe_n2f); if(cc < 0){ perror("创建管道失败"); exit(EXIT_FAILURE); } pid_n2 = fork(); if(pid_n2 < 0){ perror("创建子进程失败"); exit(EXIT_FAILURE); }else if (pid_n2 == 0){ /*孙子进程2*/ close(ns); close(pipe_n1n2[1]); close(0); dup(pipe_n1n2[0]); close(pipe_n1n2[0]); close(pipe_n2f[0]); close(1); dup(pipe_n2f[1]); close(pipe_n2f[1]); execlp("cut","cut","-f","1,4",NULL); exit(EXIT_FAILURE); } /*子进程*/ close(pipe_n1n2[0]); close(pipe_n1n2[1]); close(pipe_n2f[1]); close(0); dup(pipe_n2f[0]); close(pipe_n2f[0]); close(1); dup(ns); close(ns); execlp("head","head","-n",number,NULL); exit(EXIT_FAILURE); } close(ns); } close(sd); return 0; }
客户端代码
#include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #define BUFSIZE 4096 int main(int argc, char *argv[]){ int err; struct addrinfo hints, *res; char *remote_host; // 此处存在错误:类型应为char*而非char char remote_service; char year[BUFSIZE]; char number[BUFSIZE]; char type[BUFSIZE]; if(argc < 3){ fprintf(stderr,"参数错误:使用方式为 client server port\n"); exit(EXIT_FAILURE); } memset(&hints,0,sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; remote_host = argv[1]; remote_service = argv[2]; if((err = getaddrinfo(remote_host,&remote_service,&hints,&res)) != 0){ fprintf(stderr,"名称解析错误:%s\n",gai_strerror(err)); exit(EXIT_FAILURE); } printf("请输入出版年份:\n"); scanf("%s",year); do{ int cc, sd, i = 0; struct addrinfo *ptr; uint8_t buffer[BUFSIZE]; printf("请输入游戏数量:\n"); scanf("%s",number); printf("请输入类型:\n"); scanf("%s",type); for(ptr = res; ptr != NULL; ptr = ptr->ai_next){ if((sd = socket(ptr->ai_family,ptr->ai_socktype,ptr->ai_protocol)) < 0){ fprintf(stderr,"创建套接字失败\n"); continue; } if(connect(sd,ptr->ai_addr,ptr->ai_addrlen) == 0){ fprintf(stderr,"成功连接:%d\n",i); break; } close(sd); i++; } if(ptr == NULL){ fprintf(stderr,"无法找到对应地址\n"); exit(3); } if(write(sd,year,strlen(year)) < 0){ perror("写入年份失败"); exit(EXIT_FAILURE); } if(read(sd,buffer,sizeof(buffer)) < 0){ perror("读取年份确认信息失败"); exit(EXIT_FAILURE); } if(write(sd,number,strlen(number)) < 0){ perror("写入数量失败"); exit(EXIT_FAILURE); } if(read(sd,buffer,sizeof(buffer)) < 0){ perror("读取数量确认信息失败"); exit(EXIT_FAILURE); } if(write(sd,type,strlen(type)) < 0){ perror("写入类型失败"); exit(EXIT_FAILURE); } while((cc = read(sd,buffer,sizeof(buffer)) > 0)){ write(1,buffer,cc); } if(cc < 0){ perror("读取服务器结果失败"); exit(EXIT_FAILURE); } close(sd); printf("请输入年份(输入end终止程序):\n"); scanf("%s",year); }while(strcmp(year,"end") != 0); freeaddrinfo(res); return 0; }
问题原因及修复方案
客户端核心错误
remote_service被定义为char类型,但argv[2]是字符串指针,类型不匹配会导致getaddrinfo接收到乱码的服务名参数,直接引发名称解析失败。- 修复:将
char remote_service;改为char *remote_service;,同时getaddrinfo调用改为getaddrinfo(remote_host,remote_service,&hints,&res);(去掉remote_service的取地址符)。
服务器核心错误
getaddrinfo的第一个参数传入了stderr(文件指针),而正确用法是配合AI_PASSIVE标志传入NULL,表示绑定到本地所有可用网络接口。- 修复:将
err = getaddrinfo(stderr,service, &hints, &res);改为err = getaddrinfo(NULL,service, &hints, &res);。
主机名解析问题
- 执行命令时使用的
server主机名需要在本地/etc/hosts文件或DNS中有映射。如果是本地测试,可直接替换为localhost或127.0.0.1,避免主机名解析失败。
- 执行命令时使用的
内容的提问来源于stack exchange,提问作者Penguineer
相关产品推荐
相关产品推荐

