哪位大神进来帮忙看看linux下类似qq的程序实现功能
最近在网上找到一个类似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;
}
有点长,辛苦了