对于班级作业,我必须在客户端发送“ NEWPORT”后关闭所有打开的套接字,并将“ n-port”分配给新套接字,从那时起,我必须使用为新的传入连接创建的套接字,但是当我尝试连接到新服务器时,客户端的perror函数会告诉我“连接被拒绝”。
服务器代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define MAX_SIZE 512
void manage_connections(int fds,struct sockaddr_in serv_addr, struct sockaddr_in cl_addr, socklen_t cl_len);
int main(int argc, char* argv[]){
struct sockaddr_in serv_addr, cl_addr;
socklen_t cl_len;
int fds=0;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5200);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
fds = socket(AF_INET, SOCK_STREAM, 0);
if(fds<0){
perror("Socket error");
exit(-1);
}
if(bind(fds,(struct sockaddr*)&serv_addr, sizeof(serv_addr))<0){
perror("Bind error");
exit(-1);
}
if((listen(fds,5))<0){
perror("Listen error");
exit(-1);
}
manage_connections(fds,serv_addr, cl_addr, cl_len);
close(fds);
return 0;
}
void manage_connections(int fds,struct sockaddr_in serv_addr, struct sockaddr_in cl_addr, socklen_t cl_len){
char buffer[MAX_SIZE], cl_ip[MAX_SIZE], cl_port[MAX_SIZE], cmd_np[MAX_SIZE], cmd_np_n[MAX_SIZE], cmd_np_str[MAX_SIZE], nport[MAX_SIZE];
int i=0, port=0,fdc=0, nfds;
struct sockaddr_in nserv_addr;
while(1){
cl_len = sizeof(cl_addr);
fdc = accept(fds, (struct sockaddr*)&cl_addr, &cl_len);
if(fdc<0){
perror("Accept error");
exit(-1);
}
do{
for(i=0;i<MAX_SIZE;i++){
buffer[i]=0;
cl_ip[i]=0;
cl_port[i]=0;
cmd_np[i]=0;
cmd_np_n[i]=0;
cmd_np_str[i]=0;
nport[i]=0;
}
read(fdc,buffer, MAX_SIZE);
if(strcmp(buffer,"MYIP")==0){
strcat(cl_ip,inet_ntoa(cl_addr.sin_addr));
write(fdc,cl_ip,strlen(cl_ip));
} else if(strcmp(buffer,"MYPORT")==0){
sprintf(cl_port,"%d", (int)htons(cl_addr.sin_port));
write(fdc, cl_port, strlen(cl_port));
}else{
sscanf(buffer, "%s %d", cmd_np, &port);
sprintf(nport, "%d", port);
if(strcmp(cmd_np,"NEWPORT")==0){
strcat(cmd_np_str, "ACK ");
strcat(cmd_np_str, nport);
write(fdc, cmd_np_str,strlen(cmd_np_str));
close(fds);
close(fdc);
nserv_addr.sin_family=AF_INET;
nserv_addr.sin_port = htons(port);
nserv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
nfds = socket(AF_INET, SOCK_STREAM,0);
if(nfds<0){
perror("New socket error");
exit(-1);
}
if((bind(nfds,(struct sockaddr*)&nserv_addr,sizeof(nserv_addr)))<0){
perror("New bind error");
exit(-1);
}
if((listen(nfds,5))<0){
perror("New listen error");
exit(-1);
}
manage_connections(nfds,nserv_addr, cl_addr, cl_len);
}
}
}while(strcmp(cmd_np,"NEWPORT")!=0);
close(fdc);
}
}
客户代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>
#define MAX_SIZE 512
int main(int argc, char* argv[]){
struct sockaddr_in cl_addr;
int fdc=0,len=0, res_len=0,i=0;
char buffer[MAX_SIZE];
cl_addr.sin_family = AF_INET;
cl_addr.sin_port = htons(5200);
inet_aton("192.168.10.128",&cl_addr.sin_addr);
fdc = socket(AF_INET, SOCK_STREAM,0);
if(fdc<0){
perror("Accept error");
exit(-1);
}
if((connect(fdc, (struct sockaddr*)&cl_addr, sizeof(cl_addr)))<0){
perror("Connect error");
exit(-1);
}
while(1){
write(1, "Inserire uno tra i comandi MYIP, MYPORT, NEWPORT:\n", strlen("Inserire uno tra i comandi MYIP, MYPORT, NEWPORT:\n"));
len = read(1, buffer, MAX_SIZE);
buffer[len-1] = '\0';
write(fdc, buffer, strlen(buffer)+1);
for(i=0;i<MAX_SIZE;i++)
buffer[i]=0;
res_len = read(fdc,buffer,MAX_SIZE);
write(1,"\nResponso: ",strlen("\nResponso: "));
write(1, buffer, res_len);
write(1,"\n",strlen("\n"));
}
close(fdc);
return 0;
}
答案 0 :(得分:2)
您的客户端被硬编码为5200端口号。如果您使用NEWPORT
将服务器切换到新的服务器,则由于您正在关闭原始的监听套接字并打开新的套接字,因此服务器将不再在5200上监听。
因此,当您再次运行客户端时,它会拒绝连接,因为现在没有人在监听您要连接的套接字。
我看到的最好的解决方法是添加在客户端指定端口号作为命令行参数的功能。
代码的其他问题:
您假设将在每次调用write
时发送全部缓冲区内容,并且将在每个read
上接收全部缓冲区内容。在像这样的玩具程序中,它可以工作,但TCP不能保证。
您的manage_connections
函数是递归的,这似乎是不良的结构。足够的调用,您将用完堆栈。
没有内置的方法可以退出客户端程序。您可以按Ctrl-C终止,但是在NEWPORT
情况下,它不会检测到服务器只是关闭了连接(因为它是从终端读取的)。
您实际上是从标准 output 文件中阅读。如果您已连接到终端,那通常可以使用,但是在其他情况下则无法使用,也不是一件值得依赖的事情。
您要将cl_addr
和cl_len
变量传递到manage_connections
中,但这毫无意义。调用方不会在调用之前初始化它们,也不会在调用之后使用它们。应该只在函数内部声明它们。