gpt4 book ai didi

c - c 中的 TCP 聊天无法正确读取/发送字符串

转载 作者:行者123 更新时间:2023-11-30 14:52:17 25 4
gpt4 key购买 nike

我正在尝试实现多客户端聊天,使用基于 TCP 套接字的连接和线程来管理客户端和输入。但是,发送或接收的字符串的读写没有正确执行,我不太明白为什么。

服务器:

#define IP "127.0.0.1"
#define PORT 9000
#define MAX_CONNECTION_Q 10
#define CLIENTS 10
#define BUFFSIZE 1024
#define NAMELEN 32
#define COMMANDS 16
#define MESSAGESIZE 256
#define LINENUM 512

struct chat{
char userlist[CLIENTS][NAMELEN];
char admin[NAMELEN];
char ID[NAMELEN];
char logg[512][216];
struct chat *next;
int pos;
};

struct client_info{
pthread_t client_ID;
int sockfd;
struct chat chats;
char user[NAMELEN];
struct client_info *next;
};

struct header{
struct client_info *fnode, *lnode;
}*client_head;

struct chat_head{
struct chat *fnode,*lnode;
}*chat_head;


int sockfd, clinfo;
struct client_info thread_info[CLIENTS];
struct header client_list;
pthread_mutex_t mutex;

void list_init() {
client_head = malloc(sizeof(struct header));
chat_head = malloc(sizeof(struct chat_head));
client_head->fnode = NULL;
chat_head->fnode = NULL;
}

int compare(int a, int b){
return (a-b);
}

void chat_insert(struct chat *node){
if(chat_head->fnode == NULL){
chat_head->fnode = node;
chat_head->lnode = node;
}
else{
chat_head->lnode->next = node;
chat_head->lnode = node;
}
}

int search_cli(char *name){
struct client_info *tmp = client_head->fnode;
while(tmp!=NULL){
if(strcmp(tmp->user,name) == 0){
return tmp->sockfd;
}
tmp = tmp->next;
}
return -1;
}

void client_insert(struct client_info *node){
if(client_head->fnode == NULL){
client_head->fnode = node;
client_head->lnode = node;
node->next = NULL;
}
else{
client_head->lnode->next = node;
client_head->lnode = node;
node->next = NULL;
}
}

void client_delete(struct client_info *node){
struct client_info *last = client_head->fnode;
struct client_info *tmp = last->next;
if(client_head->fnode == NULL){
return;
}
if(compare(last->sockfd, node->sockfd) == 0){
client_head->fnode = tmp;

free(last);

if(client_head->fnode == NULL){

client_head->lnode = NULL;

}

return;
}
while(tmp!=NULL){
if(compare(tmp->sockfd, node->sockfd) == 0) {
last->next = tmp->next;

free(tmp);
return;
}

tmp = tmp->next;
}

}

void display_clients(){
struct client_info *tmp = client_head->fnode;
while(tmp!=NULL){
printf("Username: %s\nSocket: %d\n--------------------\n",tmp->user,tmp->sockfd);
tmp = tmp->next;
}
}

void change_username(int sock,char *sender){
struct client_info *tmp = client_head->fnode;
while(tmp!=NULL){
if(tmp->sockfd == sock){
strcpy(tmp->user,sender);
break;
}
tmp = tmp->next;
}
}

void *client_commands_handler(void *fd){
struct client_info *clinfo = (struct client_info *)fd;
char *buffer = malloc(NAMELEN);
char receiver[NAMELEN],sender[NAMELEN],message[BUFFSIZE];
recv(clinfo->sockfd,buffer,NAMELEN,0);
strcpy(clinfo->user,buffer);
memset(buffer,0,sizeof(buffer));
int nbytes;
while(1){
memset(buffer,0,sizeof(buffer));
nbytes = recv(clinfo->sockfd, buffer, BUFFSIZE, 0);
if(nbytes<=0) {
printf("%s lost connection\n", clinfo->user);
pthread_mutex_lock(&mutex);
client_delete(clinfo);
pthread_mutex_unlock(&mutex);
break;
}
printf("%s\n",buffer);
else if(strncmp(buffer, "private", 7) == 0) {
int sockid;
sscanf(buffer,"private %s %s %s",sender,receiver,message);
printf("%s%s%s",sender,receiver,message);
if((sockid = search_cli(sender)) == -1){
char *server = malloc(NAMELEN);
strcpy(server,"<Server> User doesn't exist\n");
write(clinfo->sockfd,server,strlen(server));
}
else{
struct chat new_chat;
new_chat.pos = 0;
strcpy(new_chat.logg[new_chat.pos],message);
new_chat.pos++;
strcpy(new_chat.userlist[0],sender);
strcpy(new_chat.userlist[1],receiver);
sprintf(new_chat.ID,"%s%s",new_chat.userlist[0],new_chat.userlist[1]);
new_chat.next = NULL;
pthread_mutex_lock(&mutex);
chat_insert(&new_chat);
pthread_mutex_unlock(&mutex);
send(sockid,message,strlen(message),0);
}
}
else {
fprintf(stderr, "Garbage data from [%d] %s...\n", clinfo->sockfd, clinfo->user);
}
}
close(clinfo->sockfd);
return NULL;
}

void *server_commands_handler() {

}

int main() {
int size,clientfd;
struct sockaddr_in server_addr, client_addr;
pthread_t server_commands;
list_init();
pthread_mutex_init(&mutex, NULL);
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Couldn't get server socket");
exit(0);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(IP);
memset(&(server_addr.sin_zero), 0, 8);
if(bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
perror("Couldn't bind socket");
exit(0);
}
if(listen(sockfd, MAX_CONNECTION_Q) == -1){
perror("Couldn't listen");
exit(0);
}
if(pthread_create(&server_commands, NULL, *server_commands_handler, NULL) != 0){
perror("Couldn't create thread");
exit(0);
}
while(1){
size = sizeof(struct sockaddr_in);
if((clientfd = accept(sockfd, (struct sockaddr *)&client_addr,(socklen_t*)&size))==-1){
perror("Connection failed");
exit(0);
}
printf("Client accepted\n");
struct client_info clinfo;
clinfo.sockfd = clientfd;
clinfo.next = NULL;
pthread_mutex_lock(&mutex);
client_insert(&clinfo);
pthread_mutex_unlock(&mutex);
pthread_create(&clinfo.client_ID, NULL, client_commands_handler, (void *)&clinfo);
}
return 0;
}

客户:

#define SERVERIP "127.0.0.1"
#define SERVERPORT 9000
#define BUFFSIZE 1024
#define USERLEN 32
#define OPTLEN 16

struct threadinfo{
pthread_t thread_ID;
int sockfd;
};

struct USER{
char user[USERLEN];
int sockfd;
char current_convo[USERLEN];
};

int isconnected, sockfd, sent;
char option[BUFFSIZE];
struct USER me;

int connect_with_server();
void logout(struct USER *me);
void login(struct USER *me);
void *receiver();

void login(struct USER *me){
if(isconnected){
printf("Already connected\n");
return;
}
sockfd = connect_with_server();
if(sockfd == -1){
perror("Couldn't connect to server\n");
}
if(sockfd >= 0) {
isconnected = 1;
me->sockfd = sockfd;
printf("Logged in as %s\n", me->user);
struct threadinfo thread;
pthread_create(&thread.thread_ID, NULL, receiver, (void *)&thread);
}
else {
printf("Couldn't connect.\n");
exit(0);
}
}

void *receiver(){
int recvd;
char msg[BUFFSIZE];
while(isconnected){
memset(msg,0,sizeof(msg));
recvd = read(sockfd, msg, sizeof(msg));
if(!recvd) {
printf("Connection Lost from Server\n");
isconnected = 0;
close(sockfd);
break;
}
if(recvd > 0) {
fputs(msg,stdout);
}
}
return NULL;
}

int main() {
memset(&me, 0, sizeof(struct USER));
char msg[BUFFSIZE];
char *token;
while(fgets(option,BUFFSIZE-1,stdin)){
memset(msg,0,sizeof(msg));
if(strncmp(option,"exit", 4) == 0){
logout(&me);
break;
}
else if(strncmp(option, "login", 5) == 0){
token = strtok(option, " ");
token = strtok(NULL, "\n");
memset(me.user, 0, sizeof(char)*USERLEN);
if(token != NULL) {
strcpy(me.user, token);
login(&me);
}
else{
printf("Couldn't get valid username\n");
}
}
else if(strncmp(option, "private", 7) == 0){
if(isconnected == 0){
printf("User not connected\n");
}
else{
char *tmp = malloc(USERLEN);
token = strtok(option, " ");
token = strtok(NULL, " ");
strcpy(tmp,token);
token = strtok(NULL, "\n");
sprintf(msg,"private %s %s %s",me.user,tmp,token);
send(sockfd, msg, strlen(msg),0);
}
}
return 0;
}

该代码有很多代码对于简单的基于双向输入的连接来说是不必要的,但是从长远来看,我正在尝试实现它,它将具有更多功能。这里有很多事情需要修复,但我的问题是主要侧重于通过“私有(private)”输入发送字符串,应如下所示:

private (username of receiver) (message to send)

最佳答案

我还在看它,但我注意到了一些事情。在您的服务器中,您有

  char *buffer = malloc(NAMELEN);
char receiver[NAMELEN],sender[NAMELEN],message[BUFFSIZE];
recv(clinfo->sockfd,buffer,NAMELEN,0);
strcpy(clinfo->user,buffer);
memset(buffer,0,sizeof(buffer));
int nbytes;
while(1){
memset(buffer,0,sizeof(buffer));
nbytes = recv(clinfo->sockfd, buffer, BUFFSIZE, 0);

缓冲区变量接收指向 NAMELEN (32) 字节 block 的指针。您无需查看状态即可接收 NAMELEN 字节。到目前为止,一切都很好。然后清除缓冲区的第一个 sizeof 字节(由于缓冲区是一个指针,因此您将清除 4 或 8 个字节)。不久之后,您将 BUFFSIZE (1024) 字节接收到可怜的 32 字节缓冲区中。

我建议您通过 telnet 测试来运行服务器

telnet 127.0.0.1 9000

并输入您的程序所期望的内容。请记住,只有当您按回车键时才会传输数据。

客户端可以通过 netcat 进行类似的练习:

nc -l 127.0.0.1 9000

当我这样做时,为什么你的客户端是多线程的?如果直接调用receiver()而不是创建另一个线程,事情会变得简单。

还要留意您的 malloc 并确保它们与 free 配对。我看到很多地方都分配了固定大小的内存块,然后不释放它。使用局部变量可以更干净地完成此操作。当你回来时,这些就会消失。或者,查看 alloca(),当您返回时它也会消失。它并非随处可用,但非常有用。

关于c - c 中的 TCP 聊天无法正确读取/发送字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47688791/

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