我正在尝试在服务器和多个客户端之间创建一个聊天室。除了将套接字绑定到随机端口之外,所有功能都可以正常运行。我通过创建一个随机端口
server_info.sin_port = htons(0);
我的问题在于客户端可以使用该端口,或者如何将端口号发送给客户端?
如果我将端口替换为静态数字(例如“ 8888”),则程序将成功运行。我在收集端口的客户端方面遇到了问题。
服务器代码
int main()
{
signal(SIGINT, catch_ctrl_c_and_exit);
// Create socket
server_sockfd = socket(AF_INET , SOCK_STREAM , 0);
if (server_sockfd == -1) {
char error[255];
sprintf(error,"Fail to create a socket.");
write(1,error,strlen(error));
exit(EXIT_FAILURE);
}
// Socket information
struct sockaddr_in server_info, client_info;
int s_addrlen = sizeof(server_info);
int c_addrlen = sizeof(client_info);
memset(&server_info, 0, s_addrlen);
memset(&client_info, 0, c_addrlen);
server_info.sin_family = PF_INET;
server_info.sin_addr.s_addr = INADDR_ANY;
//TEST
server_info.sin_port = htons(0);
// Bind and Listen
bind(server_sockfd, (struct sockaddr *)&server_info, s_addrlen);
listen(server_sockfd, 5);
// Print Server IP
char start[100];
getsockname(server_sockfd, (struct sockaddr*) &server_info, (socklen_t*) &s_addrlen);
sprintf(start,"Start Server on: %s:%d\n", inet_ntoa(server_info.sin_addr), ntohs(server_info.sin_port));
write(1,start,strlen(start));
// Initial linked list for clients
root = newNode(server_sockfd, inet_ntoa(server_info.sin_addr));
now = root;
while (1) {
client_sockfd = accept(server_sockfd, (struct sockaddr*) &client_info, (socklen_t*) &c_addrlen);
// Print Client IP
getpeername(client_sockfd, (struct sockaddr*) &client_info, (socklen_t*) &c_addrlen);
char client[255];
sprintf(client,"Client %s:%d come in.\n", inet_ntoa(client_info.sin_addr), ntohs(client_info.sin_port));
write(1,client,strlen(client));
// Append linked list for clients
ClientList *c = newNode(client_sockfd, inet_ntoa(client_info.sin_addr));
c->prev = now;
now->link = c;
now = c;
pthread_t id;
if (pthread_create(&id, NULL, (void *)client_handler, (void *)c) != 0) {
perror("Create pthread error!\n");
exit(EXIT_FAILURE);
}
}
return 0;
}
客户代码
int main()
{
signal(SIGINT, catch_ctrl_c_and_exit);
// Naming
char nick[255];
sprintf(nick,"Please enter your name: ");
write(1,nick,strlen(nick));
if (fgets(nickname, LENGTH_NAME, stdin) != NULL) {
str_trim_lf(nickname, LENGTH_NAME);
}
if (strlen(nickname) < 2 || strlen(nickname) >= LENGTH_NAME-1) {
char nameerr[100];
sprintf(nameerr,"\nName must be more than one and less than thirty characters.\n");
write(1,nameerr,strlen(nameerr));
exit(EXIT_FAILURE);
}
// Create socket
sockfd = socket(AF_INET , SOCK_STREAM , 0);
if (sockfd == -1) {
char err[100];
sprintf(err,"Fail to create a socket.");
write(1,err,strlen(err));
exit(EXIT_FAILURE);
}
// Socket information
struct sockaddr_in server_info, client_info;
int s_addrlen = sizeof(server_info);
int c_addrlen = sizeof(client_info);
memset(&server_info, 0, s_addrlen);
memset(&client_info, 0, c_addrlen);
server_info.sin_family = PF_INET;
server_info.sin_addr.s_addr = inet_addr("127.0.0.1");
//TEST
server_info.sin_port = htons(0);
// Connect to Server
int err = connect(sockfd, (struct sockaddr *)&server_info, s_addrlen);
if (err == -1) {
char err[100];
sprintf(err,"Connection to Server error!\n");
write(1,err,strlen(err));
exit(EXIT_FAILURE);
}
// Names
getsockname(sockfd, (struct sockaddr*) &client_info, (socklen_t*) &c_addrlen);
getpeername(sockfd, (struct sockaddr*) &server_info, (socklen_t*) &s_addrlen);
char conn[100];
char ipval[100];
sprintf(conn,"Connect to Server: %s:%d\n", inet_ntoa(server_info.sin_addr), ntohs(server_info.sin_port));
sprintf(ipval,"You are: %s:%d\n", inet_ntoa(client_info.sin_addr), ntohs(client_info.sin_port));
write(1,conn,strlen(conn));
write(1,ipval,strlen(ipval));
send(sockfd, nickname, LENGTH_NAME, 0);
pthread_t send_msg_thread;
if (pthread_create(&send_msg_thread, NULL, (void *) send_msg_handler, NULL) != 0) {
char err[100];
sprintf (err,"Create pthread error!\n");
write(1,err,strlen(err));
exit(EXIT_FAILURE);
}
pthread_t recv_msg_thread;
if (pthread_create(&recv_msg_thread, NULL, (void *) recv_msg_handler, NULL) != 0) {
char err[100];
sprintf(err,"Create pthread error!\n");
write(1,err,strlen(err));
exit(EXIT_FAILURE);
}
while (1) {
if(flag) {
char bye[20];
sprintf(bye,"\nBye\n");
write(1,bye,strlen(bye));
break;
}
}
close(sockfd);
return 0;
}
发现错误的原因
connect(sockfd, (struct sockaddr *)&server_info, s_addrlen);
答案 0 :(得分:1)
您可以使用与发送服务器IP地址相同的方式将端口号发送给客户端。
要通过TCP连接,客户端需要知道服务器的IP地址和非零端口号。
如果客户端和服务器在同一台计算机上运行,则通常使用文件,环境变量或剪贴板来传达IP地址和端口号。
在您的示例中,您可以将 printf 添加到server.c以打印IP地址和端口号(使用功能 getsockname 获取它们)。然后,您可以将代码添加到client.c,以从argv[1]
获取IP地址和从argv[2]
获取端口号。完成上面的代码更改后,首先启动服务器,将打印的IP地址和端口号复制到剪贴板,然后将其粘贴到客户端的命令行,然后按 Enter 启动客户端,它将在其argv
中获得这两个参数。