gpt4 book ai didi

c - 无法在客户端之间发送消息 (C)

转载 作者:太空宇宙 更新时间:2023-11-04 03:19:43 25 4
gpt4 key购买 nike

我想使用客户端-服务器(具有多个客户端的服务器)完成 minitalk。使用名称参数启动客户端,并完成与服务器的连接。

服务器记住每个客户端的名字。然后,在每个客户端中我都可以向另一个客户端发送消息 - 例如我启动了 2 个客户端 - c1 和 c2,我可以从 c1 发送消息 - c2 hello 并且它应该在 c2 中显示为已接收一。我也可以从c1发送到c1,没关系。我期望在客户端代码下方(因为服务器运行良好)

    #include <stdio.h> 
#include <string.h> //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> //close
#include <arpa/inet.h> //close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros
#define PORT 8080

int main(int argc, char *argv[])
{
struct sockaddr_in address;
int sock = 0, thisclient = 0, valread;
struct sockaddr_in serv_addr;
int activity;

fd_set readfds;

char *hello = malloc(100);
char tab[1024] = {0};
char* name = argv[1];

if((thisclient = socket(AF_INET , SOCK_STREAM , 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}

memset(&serv_addr, '0', sizeof(serv_addr));

serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);

// Convert IPv4 and IPv6 addresses from text to binary form
if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}

if (connect(thisclient, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\nConnection Failed \n");
return -1;
} else {

send(thisclient, name, strlen(name), 0);
}



valread = read(thisclient , tab, 1024);

if(strcmp(tab,name) != 0) {
printf("Already used user!");
return -1;
} else {
bzero(tab, sizeof(tab));
send(thisclient, "Connection", 11, 0);
valread = read(thisclient , tab, 1024);
printf("%s---\nSending message to not in a list causes server exiting\n---\n",tab);
bzero(tab, sizeof(tab));
}



while(1) {

FD_ZERO(&readfds);
FD_SET(0,&readfds); //stdin
FD_SET(thisclient,&readfds);

activity = select( thisclient+1 , &readfds , NULL , NULL , NULL);

if ((activity < 0) && (errno!=EINTR))
{
printf("select error");
}

for(int i=0; i<thisclient+1; ++i) {

if (FD_ISSET( i , &readfds))
{

if(i== thisclient) {
char* buffer = malloc(1025);

if ((valread = read( thisclient , buffer, 1024)) != 0) {
if(strcmp(buffer,"Server error, is closing") == 0) {
exit(0);
}

printf("Received (yours name) (message): %s\n",buffer );
bzero(buffer, sizeof(buffer));

}
free(buffer);
}
else if(i == 0) {
char* buffer = malloc(1025);
if ((valread = read( 0 , buffer, 1024)) != 0) {
if(strcmp(buffer,"Server error, is closing") == 0) {
exit(0);
}

send(thisclient, buffer, 1024, 0);
printf("Send (yours name) (message): %s\n",buffer );
bzero(buffer, sizeof(buffer));

}
free(buffer);
}
}
}

}
return 0;
}

我应该能够像“乒乓球”一样发送消息,所以 c1 发送给 c2,c2 发送给 c1,c1 发送两条消息给 c2,c2 发送一条消息给 c1 等等。

目前,连接正常,然后我发送第一条消息(发送者和接收者是谁并不重要,例如 c1 发送给 c2)。我可以从 c1 向 c2 发送许多消息,但是当我想响应时(从 c2 到 c1 的消息)什么也没有发生。

我还注意到,这条消息甚至不是服务器发出的,所以这肯定是客户端的错。我仍然可以从 c1 向 c2 发送消息,但不能由内而外。是什么“刷新”了这个状态?我从 c1 向 c1 发送一条消息。在此消息之后,c2 中的先前消息也显示在 c1 中(最近从 c1 到 c1)。但是每次我想从 c2 接收消息时,我都必须“刷新”。

我应该在 select() 调用中添加一些东西吗? (例如用于写入的参数)。还是循环没做好?

-编辑服务器代码

#include <stdio.h> 
#include <string.h> //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> //close
#include <arpa/inet.h> //close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros

#define TRUE 1
#define FALSE 0
#define PORT 8080

int main(int argc , char *argv[])
{
int opt = TRUE;
int master_socket , addrlen , new_socket , client_socket[30] ,
max_clients = 30 , activity, i , valread , sd;
int max_sd;
struct sockaddr_in address;

char client_name[30][100];


//set of socket descriptors
fd_set readfds;

//initialise all client_socket[] to 0 so not checked
for (i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}

//create a master socket
if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}

//set master socket to allow multiple connections ,
//this is just a good habit, it will work without this
if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
sizeof(opt)) < 0 )
{
perror("setsockopt");
exit(EXIT_FAILURE);
}

//type of socket created
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );

//bind the socket to localhost port 8888
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("Listener on port %d \n", PORT);

//try to specify maximum of 3 pending connections for the master socket
if (listen(master_socket, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}

//accept the incoming connection
addrlen = sizeof(address);
puts("Waiting for connections ...");

while(TRUE)
{
//clear the socket set
FD_ZERO(&readfds);

//add master socket to set
FD_SET(master_socket, &readfds);
max_sd = master_socket;

//add child sockets to set
for ( i = 0 ; i < max_clients ; i++)
{
//socket descriptor
sd = client_socket[i];

//if valid socket descriptor then add to read list
if(sd > 0)
FD_SET( sd , &readfds);

//highest file descriptor number, need it for the select function
if(sd > max_sd)
max_sd = sd;
}

//wait for an activity on one of the sockets , timeout is NULL ,
//so wait indefinitely
activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);

if ((activity < 0) && (errno!=EINTR))
{
printf("select error");
}

//If something happened on the master socket ,
//then its an incoming connection
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket,
(struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}

//inform user of socket number - used in send and receive commands
printf("New connection, ip- %s, port- %d\n" , inet_ntoa(address.sin_addr) , ntohs
(address.sin_port));

char* tempclient = malloc(100);
read(new_socket, tempclient, 100);


//add new socket to array of sockets
for (i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
strcpy(client_name[i], tempclient);
printf("Adding to list of sockets as %s - pos %d\n",client_name[i],i);
send(new_socket, client_name[i], strlen(client_name[i]), 0);
read(new_socket, tempclient, 100);

char list[1000];
strcpy(list, "List of users\n");
for(int j=0; client_socket[j] != 0; ++j) {
strcat(list, client_name[j]);
strcat(list,"\n");
}
send(new_socket, list, strlen(list), 0);
break;
} else if(strcmp(client_name[i],tempclient) == 0) {
send(new_socket, "ERROR", 5, 0);
break;
} else if(strcmp(tempclient,"exit ") == 0) {
send(new_socket, "ERROR", 5, 0);
break;
}
}
}

//else its some IO operation on some other socket
for (i = 0; i < max_clients; i++)
{
char* buffer = malloc(1025);
char* name = malloc(100);
sd = client_socket[i];

if (FD_ISSET( sd , &readfds))
{

//Check if it was for closing , and also read the
//incoming message
if ((valread = read( sd , buffer, 1024)) == 0)
{
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&address , \
(socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" ,
inet_ntoa(address.sin_addr) , ntohs(address.sin_port));

//Close the socket and mark as 0 in list for reuse
close( sd );
client_socket[i] = 0;
}
//Echo back the message that came in
else {
strcpy(name, buffer);
strtok(name, " ");
puts("bufor = ");
puts( buffer);
for (i = 0; i < max_clients; i++) //loop seraching for name
{
if( client_socket[i] != 0 ) { //client in array
if(strcmp(client_name[i], name) == 0) {// message name same as client name

send(client_socket[i] , buffer , 1024 , 0 );
bzero(buffer, sizeof(buffer));
bzero(name, sizeof(name));
break;
}
}
else { //no more clients
for (i = 0; i < max_clients; i++) //loop after clients
{
if( client_socket[i] != 0 ) { //send error
send(client_socket[i], "Server error, is closing", 30, 0);
} else break;
}

puts("Message error, whole communication is closing\n");
exit(0);
}
}
bzero(buffer, sizeof(buffer));
bzero(name, sizeof(name));
}
}
free(buffer);
free(name);
}

}

return 0;
}

最佳答案

主要错误在服务器的这些循环中:

        //else its some IO operation on some other socket
for (i = 0; i < max_clients; i++)
{

//Check if it was for closing , and also read the
//incoming message
if ((valread = read( sd , buffer, 1024)) == 0)

//Echo back the message that came in
else {

for (i = 0; i < max_clients; i++) //loop seraching for name

break;

}

}

内部循环中使用了与外部循环中相同的循环变量 i,导致尝试读取相同的客户端消息两次,从而阻塞服务器,直到该客户端重新发送消息。

第二个错误是 tempclient 尽管用作字符串,但并不总是以 null 结尾。快速修复:将 char* tempclient = malloc(100) 替换为 char *tempclient = calloc(100, 1)

关于c - 无法在客户端之间发送消息 (C),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47649730/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com