我正在编写一个使用TCP通过网络进行通信的聊天室程序。如果用户提供ip地址作为命令行参数,程序将尝试连接到该地址。如果没有,服务器将等待其他人连接。 服务器接收客户端发送的任何文本消息都没有问题。但是,客户端仅在发送自己的消息时才从服务器接收文本消息。我如何解决这个问题,以便客户端立即收到消息?这是我的代码
服务器代码:
#define MAX_CLIENTS 100
static unsigned int cli_count = 0;
static int uid = 10;
typedef struct {
struct sockaddr_in addr;
int connfd;
int uid;
char name[32];
} client_t;
client_t *clients[MAX_CLIENTS];
void queue_add(client_t *cl)
{
int i;
for(i=0;i<MAX_CLIENTS;i++)
{
if(!clients[i])
{
clients[i] = cl;
return;
}
}
}
void queue_delete(int uid)
{
int i;
for(i=0;i<MAX_CLIENTS;i++)
{
if(clients[i])
{
if(clients[i]->uid == uid)
{
clients[i] = NULL;
return;
}
}
}
}
void send_message_all(char *s)
{
int i;
for(i=0;i<MAX_CLIENTS;i++)
{
if(clients[i])
{
write(clients[i]->connfd, s, strlen(s));
}
}
}
void *hanle_client(void *arg)
{
char buff_in[256];
char buff_out[256];
int rlen;
cli_count++;
client_t *cli = (client_t *)arg;
sprintf(buff_out, "<<JOIN, HELLO %s\r\n", cli->name);
send_message_all(buff_out);
bzero(buff_in,sizeof(buff_in));
while((rlen = read( cli->connfd,buff_in,sizeof(buff_in)-1))>0)
{
sprintf(buff_out, "[%s] %s\r\n", cli->name, buff_in);
send_message_all(buff_out);
}
close(cli->connfd);
/* Delete client from queue and yeild thread */
queue_delete(cli->uid);
free(cli);
cli_count--;
pthread_detach(pthread_self());
return NULL;
}
int main(int argc, char *argv[])
{
int listenfd = 0, connfd = 0, portno;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
pthread_t tid;
if (argc < 2) {
printf("ERROR, no port provided\n");
exit(1);
}
//Create socket
listenfd= socket(AF_INET , SOCK_STREAM , 0);
if (listenfd == -1)
{
printf("Could not create socket");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(portno);
/* Bind */
if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
{
perror("Socket binding failed");
return 1;
}
/* Listen */
if(listen(listenfd, 10) < 0)
{
perror("Socket listening failed");
return 1;
}
printf("<[SERVER STARTED]>\n");
socklen_t clilen = sizeof(cli_addr);
/* Accept clients */
while( (connfd = accept(listenfd, (struct sockaddr *)&cli_addr, (socklen_t*)&clilen)))
{
/* Client settings */
client_t *cli = (client_t *)malloc(sizeof(client_t));
cli->addr = cli_addr;
cli->connfd = connfd;
cli->uid = uid++;
sprintf(cli->name, "%d", cli->uid);
/* Add client to the queue and fork thread */
queue_add(cli);
pthread_create(&tid, NULL, &hanle_client, (void*)cli);
}
}
客户代码:
int main(int argc , char *argv[])
{
int sockfd, portno ;
struct sockaddr_in serv_addr;
struct hostent *server;
char message[2000],server_reply[2000];
if (argc <3)
{
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(1);
}
portno = atoi(argv[2]);
//Create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("ERROR opening socket");
exit(1);
}
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);
//Connect to remote server
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
{
perror("ERROR connecting");
exit(1);
}
puts("Connected\n");
//keep communicating with server
while(1)
{
//Receive a reply from the server
bzero(server_reply,2000);
if( recv(sockfd , server_reply , 2000,0) < 0)
{
puts("recv failed");
break;
}
printf("%s", server_reply);
server_reply[0]='\0';
//Send Message to server
printf("Enter Message:");
bzero(message,2000);
fgets(message, sizeof(message),stdin);
if(send(sockfd , message , strlen(message),0) < 0)
{
puts("Send failed");
return 0;
}
}
close(sockfd);
return 0;
}
答案 0 :(得分:0)
我不确定我是否正确理解了您的问题。但在较高级别,我注意到在调用close(cli->connfd)
后,您的sendall
方法在客户端套接字上调用close(cli->connfd);
/* Delete client from queue and yeild thread */
queue_delete(cli->uid);
free(cli);
cli_count--;
。在调用close之后,您将从队列中删除客户端详细信息。这样,被删除的客户端将永远不会收到任何未来的消息。你确定这是你想要的吗?
尝试删除这些行并检查这是否是您想要的 -
{{1}}
这样,只要服务器收到消息,它就会尝试将其发送给连接到服务器的所有客户端。
注意:您的代码不是线程安全的,并且会导致意外行为,因为您在不使用互斥锁的情况下从线程中访问全局数据。