|
最近在网上找到一个类似qq的程序,我在虚拟机下的Ubuntu运行,只是知道用户登录和聊天的实现,但是对如何传送文件及其他功能还不是太了解,哪位大神帮忙看看,万分感谢~~~
代码如下: // qqserver.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <signal.h> #define CLIENT_LOGIN 100 #define CLIENT_CHAT 200 #define CLIENT_QUIT 300 #define SERVER_CHAT 400 #define SERVER_QUIT 500 #define CLIENT_ONLINE 600 struct node { char name[20]; struct sockaddr_in client_addr; struct node *next; }; struct message { long type; char name[20];//保存用户名 char file_name[128];//保存发送文件的名字 char dest[20];//保存目标用户名 char mtext[512];//消息正文 }; struct node *create_list(void); void insert_list(struct node *, char *, struct sockaddr_in *); void delete_list(struct node *, char *); void recv_message(int , struct node *); void send_message(int , struct sockaddr *, pid_t); void send_to_someone(int , struct node *, struct message *); void send_to_all(int, struct node *, struct message *); void client_login(int , struct node *, struct message *, struct sockaddr_in *); void client_online(int , struct node *, struct message *); void client_chat(int , struct node *, struct message *); void client_quit(int , struct node *, struct message *); void server_chat(int , struct node *, struct message *); void server_quit(int , struct node *, struct message *); int main(int argc, const char *argv[]) { int socket_fd; pid_t pid; struct sockaddr_in server_addr; struct node *head; if (argc < 3) { fprintf(stderr, "usages : %s ip port\n", argv[0]); exit(-1); } if ((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("failed to create socket"); exit(-1); } head = create_list(); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(atoi(argv[2])); server_addr.sin_addr.s_addr = inet_addr(argv[1]); if (bind(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("failed to bind"); exit(-1); } if ((pid = fork()) < 0) { perror("failed to fork pid"); exit(-1); } if (pid == 0) recv_message(socket_fd, head); else send_message(socket_fd, (struct sockaddr *)&server_addr, pid); return 0; } struct node *create_list(void) { struct node *head; head = (struct node *)malloc(sizeof(struct node)); head->next = NULL; return head; } void insert_list(struct node *head, char *name, struct sockaddr_in *client_addr) { struct node *new; new = (struct node *)malloc(sizeof(struct node)); strcpy(new->name, name); new->client_addr = *client_addr; new->next = head->next; head->next = new; return ; } void delete_list(struct node *head, char *name) { struct node *p = head->next; struct node *q = head; while (p != NULL) { if (strcmp(p->name, name) == 0) break; p = p->next; q = q->next; } q->next = p->next; p->next = NULL; free(p); return ; } void recv_message(int socket_fd, struct node *head)//接受客户端发送过来的消息 { struct message msg; struct sockaddr_in client_addr; int client_addrlen = sizeof(struct sockaddr); while (1) { if (recvfrom(socket_fd, &msg, sizeof(msg), 0, (struct sockaddr *)&client_addr, &client_addrlen) < 0) { perror("failed to recvform client"); exit(-1); } switch(msg.type) { case CLIENT_LOGIN: client_login(socket_fd, head, &msg, &client_addr); break; case CLIENT_ONLINE: client_online(socket_fd, head, &msg); break; case CLIENT_CHAT: client_chat(socket_fd, head, &msg); break; case CLIENT_QUIT: client_quit(socket_fd, head, &msg); break; case SERVER_CHAT: server_chat(socket_fd, head, &msg); break; case SERVER_QUIT: server_quit(socket_fd, head, &msg); break; default: break; } } return ; } void send_message(int socket_fd, struct sockaddr *server_addr, pid_t pid)//用于服务器向所有在线用户发送消息 { struct message msg; char buf[512]; while(1) { memset(buf, 0, sizeof(buf)); memset(&msg, 0, sizeof(msg)); usleep(500); printf(">");//输入通信内容 fflush(stdout); fgets(buf, sizeof(buf), stdin); buf[strlen(buf) - 1] = 0; strcpy(msg.mtext, buf); msg.type = SERVER_CHAT; if (strncmp(buf, "quit", 4) == 0) { msg.type = SERVER_QUIT; sendto(socket_fd, &msg, sizeof(msg), 0, server_addr, sizeof(struct sockaddr)); kill(pid, SIGKILL); waitpid(pid, NULL, 0); exit(0); } sendto(socket_fd, &msg, sizeof(msg), 0, server_addr, sizeof(struct sockaddr)); } } void client_login(int socket_fd, struct node *head, struct message *msg, struct sockaddr_in *client_addr) { printf("********Login In********\n"); printf("%s is Login In\n", msg->name); printf("************************\n"); insert_list(head, msg->name, client_addr); send_to_all(socket_fd, head, msg);//向其他用户发送该用户的登录信息 return ; } void client_online(int socket_fd, struct node *head, struct message *msg)//把在线人员信息发送给客户端 { // printf("=======Online Msg=======\n"); struct node *p = head->next, *q = NULL; char buf[20]; bzero(msg->mtext,20); while(p != NULL) { if(strcmp(p->name, msg->name) == 0) { q = p; } else { sprintf(buf,"%s ",p->name); strcat(msg->mtext, buf); } p = p->next; } sendto(socket_fd, msg, sizeof(struct message), 0, (struct sockaddr *)&(q->client_addr), sizeof(struct sockaddr)); // printf("************************\n"); return ; } void client_chat(int socket_fd, struct node *head, struct message *msg) { printf("********Group Chat********\n"); if(strlen(msg->file_name) == 0)//通过file_name成员是否为空判断是否要发送文件 { printf("from:%s to:%s\n", msg->name,msg->dest); printf("msg: %s\n", msg->mtext); } else { printf("send file:%s\n",msg->file_name); } printf("**************************\n"); if(strncmp("all", msg->dest, 3) != 0)//根据发送用户名确定是单个发送还是全体发送 send_to_someone(socket_fd, head, msg); else send_to_all(socket_fd, head, msg); return ; } void client_quit(int socket_fd, struct node *head, struct message *msg) { printf("*********Quit Msg********\n"); printf("%s is Quit\n", msg->name); printf("*************************\n"); delete_list(head, msg->name); send_to_all(socket_fd, head, msg); return ; } void server_quit(int socket_fd, struct node *head, struct message *msg) { printf("server_quit()...\n"); send_to_all(socket_fd, head, msg); return ; } void server_chat(int socket_fd, struct node *head, struct message *msg) { printf("server_chat()...\n"); printf("server msg:%s\n",msg->mtext); send_to_all(socket_fd, head, msg); return; } void send_to_someone(int socket_fd, struct node *head, struct message *msg)//向指定用户发送消息 { printf("send_to_someone()...\n"); struct node *p = head->next; while(p != NULL) { if (strcmp(p->name, msg->dest) != 0) { p = p->next; continue; } sendto(socket_fd, msg, sizeof(struct message), 0, (struct sockaddr *)&p->client_addr, sizeof(struct sockaddr)); break; } printf("send_to_someone()...end!\n"); return ; } void send_to_all(int socket_fd, struct node *head, struct message *msg)//向所有在线用户发送消息 { printf("send_to_all()...\n"); struct node *p = head->next; while(p != NULL) { if (strcmp(p->name, msg->name) == 0) { p = p->next; continue; } sendto(socket_fd, msg, sizeof(struct message), 0, (struct sockaddr *)&p->client_addr, sizeof(struct sockaddr)); printf("send to all:%s\n",msg->mtext); p = p->next; } printf("send_to_all()...end!\n"); return ; }
//qqclient.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <signal.h> #define CLIENT_LOGIN 100 #define CLIENT_CHAT 200 #define CLIENT_QUIT 300 #define SERVER_CHAT 400 #define SERVER_QUIT 500 #define CLIENT_ONLINE 600 struct message { long type; char name[20];//保存用户名 char file_name[128];//保存发送文件的名字 char dest[20];//保存目标用户名 char mtext[512];//消息正文 }; void recv_message(int ); void send_message(int , struct sockaddr_in *, char *, pid_t); void login_msg(struct message *); void group_msg(int sockfd, struct message *msg); void quit_msg(struct message *); void server_msg(struct message *); void server_quit(void); void online_msg(struct message *msg); void send_file(int socked_fd, struct message *msg, struct sockaddr *addr); void recv_file(int sockfd, struct message *msg); void send_string(int socked_fd, struct message *msg, struct sockaddr *addr); int main(int argc, char *argv[]) { pid_t pid; int server_fd; struct sockaddr_in server_addr; if (argc < 4) { fprintf(stderr, "usages: %s ip port name\n", argv[0]); exit(-1); } if ((server_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("failed to create server_fd"); exit(-1); } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(atoi(argv[2])); server_addr.sin_addr.s_addr = inet_addr(argv[1]); if ((pid = fork()) < 0) { perror("failed to fork pid"); exit(-1); } if (pid == 0) recv_message(server_fd); else send_message(server_fd, &server_addr, argv[3], pid); return 0; } void recv_message(int server_fd)//接收服务器发送的消息 { struct message msg; while (1) { memset(&msg, 0, sizeof(msg)); if (recvfrom(server_fd, &msg, sizeof(msg), 0, NULL, NULL) < 0) { perror("failed to recv server message"); exit(-1); } // printf("msg.type=%ld\n",msg.type); switch(msg.type) { case CLIENT_LOGIN: login_msg(&msg); break; case CLIENT_CHAT: group_msg(server_fd, &msg); break; case CLIENT_QUIT: quit_msg(&msg); break; case CLIENT_ONLINE: online_msg(&msg); break; case SERVER_CHAT: server_msg(&msg); break; case SERVER_QUIT: server_quit(); break; default: break; } } return ; } void send_message(int server_fd, struct sockaddr_in *server_addr, char *name, pid_t pid)//向服务器发送消息 { struct message msg; char buf[512]; bzero(&msg, sizeof(msg)); msg.type = CLIENT_LOGIN;//发送登录信息 strcpy(msg.name, name); if (sendto(server_fd, &msg, sizeof(msg), 0, (struct sockaddr *)server_addr, sizeof(struct sockaddr)) < 0) { perror("failed to send login message"); exit(-1); } msg.type = CLIENT_ONLINE;//发送查询在线信息 strcpy(msg.name, name); if (sendto(server_fd, &msg, sizeof(msg), 0, (struct sockaddr *)server_addr, sizeof(struct sockaddr)) < 0) { perror("failed to send online message"); exit(-1); } while(1) { memset(buf, 0, sizeof(buf)); memset(&msg, 0, sizeof(msg)); usleep(500); printf("to:");//输入要通信的对方用户名,若是"all",表示向所有用户发送 fflush(stdout); fgets(buf, sizeof(buf), stdin); buf[strlen(buf) - 1] = 0; strcpy(msg.dest, buf); printf(">");//输入通信内容 fflush(stdout); fgets(buf, sizeof(buf), stdin); buf[strlen(buf) - 1] = 0; if(strncmp(buf, "FILE", 4) == 0)//表示要传送文件 { printf("Input file name:"); fgets(msg.file_name, sizeof(msg.file_name), stdin); (msg.file_name)[strlen(msg.file_name)-1] = 0; } strcpy(msg.mtext, buf); strcpy(msg.name, name); msg.type = CLIENT_CHAT; if (strncmp(buf, "quit", 4) == 0) { msg.type = CLIENT_QUIT; if (sendto(server_fd, &msg, sizeof(msg), 0, (struct sockaddr *)server_addr, sizeof(struct sockaddr)) < 0) { perror("failed to send quit message"); exit(-1); } kill(pid, SIGKILL); waitpid(pid, NULL, 0); exit(0); } send_string(server_fd, &msg, (struct sockaddr *)server_addr); if(strncmp(msg.mtext, "FILE", 4) == 0)//如果通信内容显示要传送文件,则进行传送文件处理 send_file(server_fd, &msg, (struct sockaddr *)server_addr); } return ; } void login_msg(struct message *msg)//显示登录信息 { printf("######## Login in ########\n"); printf("%s is login in\n", msg->name); printf("######## Login in ########\n"); return ; } void online_msg(struct message *msg)//显示在线用户信息 { printf("======== Online Msg =======\n"); printf("%s is online\n",msg->mtext); printf("======== Online Msg =======\n"); } void group_msg(int sockfd, struct message *msg)//显示聊天信息 { printf("******** Group Msg ********\n"); printf("from: %s\n", msg->name); printf("msg: %s\n", msg->mtext); if(strncmp(msg->mtext, "FILE", 4) == 0)//如果发送过来的消息是要接收文件,则进行接收文件处理 { printf("recv file:%s\n",msg->file_name); recv_file(sockfd, msg); } printf("******** Group Msg ********\n"); printf("to:"); fflush(stdout); return ; } void quit_msg(struct message *msg) { printf("######## Quit Msg ########\n"); printf("%s is Quit\n", msg->name); printf("######## Quit Msg ########\n"); return ; } void server_msg(struct message *msg)//显示服务器发送的信息 { printf("******** Server Msg ********\n"); printf("server msg: %s\n", msg->mtext); printf("******** Server Msg ********\n"); return ; } void server_quit(void ) { kill(getppid(), SIGKILL); exit(0); } void recv_file(int sockfd, struct message *msg)//接收文件 { FILE *fp; strcat(msg->file_name, "_copy");//在原文件名后添加_copy作为新文件名 printf("start creat new file:%s\n",msg->file_name); fp = fopen(msg->file_name, "w"); if(fp == NULL) { perror("open file error"); return; } int write_bytes = 0; int len; while(recvfrom(sockfd, msg, sizeof(struct message), 0, NULL, NULL) > 0)//接收消息,并把消息内的正文写入文件 { if(strncmp(msg->mtext, "end", 3) == 0) break; len = strlen(msg->mtext); write_bytes = fwrite(msg->mtext, 1, len, fp); printf("write_bytes=%d\n",write_bytes); } printf("end recv_file()...\n"); fclose(fp); return; } void send_string(int socket_fd, struct message *msg, struct sockaddr *addr)//发送普通消息 { printf("start send_string()...\n"); if(sendto(socket_fd, msg, sizeof(struct message), 0, addr, sizeof(struct sockaddr)) < 0) { perror("failed to send string"); return; } printf("end send_string()...\n"); } void send_file(int socket_fd, struct message *msg, struct sockaddr *addr)//发送文件 { printf("start send_file()...\n"); FILE *fp; char buf[512]; // printf("filename:%s",msg->file_name); fp = fopen(msg->file_name, "r"); if(fp == NULL) { perror("fopen error"); return ; } int read_bytes = 0; while((read_bytes = fread(buf, 1, 512, fp)) > 0)//传送文件 { printf("read_bytes=%d\n",read_bytes); strncpy(msg->mtext, buf, read_bytes); if(sendto(socket_fd, msg, sizeof(struct message), 0, addr, sizeof(struct sockaddr)) < 0) { perror("failed to send file"); return; } bzero(msg->mtext, sizeof(msg->mtext)); } strcpy(msg->mtext, "end");//发送文件结束标志 if(sendto(socket_fd, msg, sizeof(struct message), 0, addr, sizeof(struct sockaddr)) < 0) { perror("failed to send 'end'"); return; } fclose(fp); printf("end send_file()...\n"); return; }
有点长,辛苦了
|