#include "include/tcp.h" #include "include/udp.h" #include "include/mychat.h" #if 1 #define SELF_PORT_UDP 5002 #define SELF_PORT_TCP 5003 #define SELF_IP "192.168.188.136" //自己IP #define OTHER_PORT_UDP 5004 #define OTHER_PORT_TCP 5005 #define OTHER_IP "192.168.188.136" //他人IP #define BROADCAST_SEND_PORT_UDP 5200 #define BROADCAST_RECV_PORT_UDP 5300 #define BROADCAST_RECV_IP INADDR_ANY //广播IP #define BROADCAST_SEND_IP INADDR_BROADCAST //广播IP #else #define OTHER_PORT_UDP 5002 #define OTHER_PORT_TCP 5003 #define OTHER_IP "192.168.188.136" //自己IP #define SELF_PORT_UDP 5004 #define SELF_PORT_TCP 5005 #define SELF_IP "192.168.188.136" //他人IP #define BROADCAST_RECV_PORT_UDP 5200 #define BROADCAST_SEND_PORT_UDP 5300 #define BROADCAST_RECV_IP INADDR_ANY //广播IP #define BROADCAST_SEND_IP INADDR_BROADCAST //广播IP #endif #define NO_FIND 0 #define HAVE_FIND 1 LIST_HEAD(udp_data_head); //聊天数据 struct list_head *p1 = NULL; struct servmsg_udp *pos1 = NULL; LIST_HEAD(udp_online_head); //用户列表 struct list_head *p2 = NULL; struct user_info *pos2 = NULL; LIST_HEAD(tcp_data_head); //下载数据 struct list_head *p3 = NULL; struct servmsg_tcp *pos3 = NULL; LIST_HEAD(tcp_accept_head); //下载允许用户 struct list_head *p4 = NULL; struct down_info *pos4 = NULL; int I_UDP=0; //聊天数 int J_UDP=0; //上线数 int I_TCP=0; //文件数 int J_TCP=0; //下载数 pthread_mutex_t lock1; char DATAIN[UDP_MAXSIZE+1]; //输入的内容 int DOWN_IF_IN = 0; //下载确认输入 int CHANGE_AIM_IF_IN =0; //改变对象选择输入 int IF_CHAT_IN = 1; //等待聊天输入完成 int IF_ORD_IN = 1; //等待命令输入完成 int DOWN_READY_IF = 0; //下载准备 int IF_DOWN = 0; //0已经下线,1已经上线 char UP_WAY[50]; //上传路径 char DOWN_WAY[50]; //下载路径 char DOWN_NAME[20]; //下载文件名 char MY_NAME[20]; //自己的名字 struct sockaddr_in SELF_UDP_ADDR; //自己UDP信息,上线信息 struct sockaddr_in SELF_TCP_ADDR; //自己TCP信息,上线信息 //char AIM_NAME[20]; //目标的名字 struct sockaddr_in OTHER_UDP_ADDR;//他人UDP信息,临时通讯地址 struct sockaddr_in OTHER_TCP_ADDR;//他人TCP信息,临时通讯地址 /**************************************以下UDP部分*******************************************/ /*UDP发送数据*/ void play(void); void up_ord(void); void order_or_chat(char *ord); char read_file(struct sockaddr_in *cin, char *way); char *addr_return_name(struct sockaddr_in *addr); struct sockaddr_in *name_reurn_addr(int type, char *aim_name); int send_online_info(void) { /*上线信息*/ struct msg_udp usron; //填写数据包信息 usron.type_udp = LOG_IN; //聊天类型 strcpy(usron.self_name, MY_NAME); //自己名字 strcpy(usron.aim_name, "*no*"); //目标名字 usron.data_size = strlen("*no*"); //消息大小 strcpy(usron.data, "*no*"); //数据 memcpy(&usron.self_addr_udp, &SELF_UDP_ADDR, sizeof(SELF_UDP_ADDR)); //自己UDP地址 memcpy(&usron.self_addr_tcp, &SELF_TCP_ADDR, sizeof(SELF_TCP_ADDR)); //自己TCP地址 strcpy((char *)&usron.aim_addr_udp, "*no*"); //目标地址 int ret = -1; ret = udp_broad_send_to(BROADCAST_SEND_IP, BROADCAST_SEND_PORT_UDP, &usron, sizeof(usron)); //广播IP 255 if(ret == -1) { pr_debug("广播失败!\n"); return -1; } return 0; } /*UDP登入*/ void loading_udp(void) { int ret = -1; if (IF_DOWN == 0) { do { ret = send_online_info(); pr_debug("正在登入中...\n"); } while (ret != 0); IF_DOWN = 1; } } int udp_linked_list_add(struct msg_udp *msg) { switch (msg->type_udp) { case LOG_IN: //登入 { char *name_p = msg->self_name; if(!(name_p && name_p > 0 && strlen(name_p) < 20 && strncmp(name_p, MY_NAME, strlen(MY_NAME)) != 0)) break; int finded_name = NO_FIND; struct list_head *n2 = NULL; list_for_each_safe(p2, n2, &udp_online_head) //安全遍历上线 { pos2 = list_entry(p2, struct user_info, user_info_list); if (strncmp(msg->self_name, pos2->user_name, strlen(pos2->user_name)) == 0) { finded_name = HAVE_FIND; } } if (finded_name != HAVE_FIND) //没有找到此用户,则加入 { struct user_info *newmsg; newmsg = (struct user_info *)malloc(sizeof(struct user_info)); //1.填写IP与端口 memcpy(&(newmsg->user_name), msg->self_name, sizeof(msg->self_name)); //客户名 (newmsg->id)++; //id memcpy(&(newmsg->cli_addr_udp), &msg->self_addr_udp, sizeof(msg->self_addr_udp)); //UDP IP地址与端口号 memcpy(&(newmsg->cli_addr_tcp), &msg->self_addr_tcp, sizeof(msg->self_addr_tcp)); //TCP IP地址与端口号 //2.加入链表 list_add_tail(&newmsg->user_info_list, &udp_online_head); J_UDP++; //3.显示客户登入信息 printf("[%s]上线了!\n", msg->self_name); char addr[16]; u_short port1,port2; inet_ntop(AF_INET, (void *)&(newmsg->cli_addr_udp.sin_addr.s_addr), addr, sizeof(addr)); port1 = ntohs(newmsg->cli_addr_udp.sin_port); port2 = ntohs(newmsg->cli_addr_tcp.sin_port); printf("客户上线信息:%s:UDP[%d] TCP[%d]\n", addr, port1, port2); finded_name = NO_FIND; //4.重新广播 int ret = -1; ret = send_online_info(); // 自己“已上线”信息 do{ sleep(3); ret = send_online_info(); // 自己“已上线”信息 }while (ret == -1); } break; } case OFFLINE: //下线 { struct list_head *n2 = NULL; list_for_each_safe(p2, n2, &udp_online_head) //安全遍历上线 { pos2 = list_entry(p2, struct user_info, user_info_list); if (strncmp(msg->self_name, pos2->user_name, strlen(pos2->user_name)) == 0) { printf("[%s]下线!\n", pos2->user_name); J_UDP--; list_del(&pos2->user_info_list); //删除用户 free(pos2); } } break; } case CHAT_ONE: //私聊 { struct servmsg_udp *newmsg; newmsg = (struct servmsg_udp *)malloc(sizeof(struct servmsg_udp)); if(strncmp(msg->aim_name, MY_NAME, strlen(MY_NAME)) == 0) //接受的数据包,如果是发给自己的,就加入链表;否则丢弃 { //1.添加尾部 memcpy(&(newmsg->recvmsg), msg, sizeof(struct msg_udp)); //数据 //2.加入链表 list_add_tail(&newmsg->servmsg_udp_list, &udp_data_head); I_UDP++; } //修改聊天对象 char *aim_name, *aim_name_of_other; struct sockaddr_in *addr_udp_find; aim_name = addr_return_name(&msg->self_addr_udp); aim_name_of_other = addr_return_name(&OTHER_UDP_ADDR); addr_udp_find = name_reurn_addr(1, aim_name); // pr_debug("上个对话:%s, 将要对话:%s\n",aim_name,aim_name_of_other); if(aim_name == NULL || addr_udp_find == NULL) ; else if (aim_name_of_other == NULL) { pr_debug("修改对象为:%s\n->",aim_name); udp_info_check(addr_udp_find); bzero(&OTHER_UDP_ADDR, sizeof(struct sockaddr_in)); memcpy(&OTHER_UDP_ADDR, addr_udp_find, sizeof(struct sockaddr_in)); aim_name = addr_return_name(&OTHER_UDP_ADDR); pr_debug("现在对象为:%s\n",aim_name); } else if(strncmp(aim_name, aim_name_of_other, strlen(aim_name_of_other)) != 0) { char reply; printf("是否改变聊天对象为:[%s]? ++y/++n", aim_name); while(CHANGE_AIM_IF_IN != 1) { printf("等待输入...\n"); sleep(1); } reply = DATAIN[0]; CHANGE_AIM_IF_IN = 0; if(reply == 'y') { bzero(&OTHER_UDP_ADDR, sizeof(struct sockaddr_in)); memcpy(&OTHER_UDP_ADDR, addr_udp_find, sizeof(struct sockaddr_in)); } else if (reply == 'n') { ; } } break; } case CHAT_ALL: //群发 { struct servmsg_udp *newmsg; newmsg = (struct servmsg_udp *)malloc(sizeof(struct servmsg_udp)); //1.添加尾部 memcpy(&(newmsg->recvmsg), msg, sizeof(struct msg_udp)); //数据 //2.加入链表 list_add_tail(&newmsg->servmsg_udp_list, &udp_data_head); I_UDP++; break; } case REFRESH: //列表 登入类型中 已加入 { /* pr_debug("[%s]请求列表!\n", msg->self_name); struct servmsg_udp *newmsg; newmsg = (struct servmsg_udp *)malloc(sizeof(struct servmsg_udp)); //1.添加尾部 memcpy(&(newmsg->recvmsg), &msg, sizeof(msg)); //数据 //2.修改类型,通过私聊发送 newmsg->recvmsg.type_udp = CHAT_ONE; //3.添加内容data strcpy(newmsg->recvmsg.data, "用户列表:"); struct list_head *n2 = NULL; list_for_each_safe(p2, n2, &udp_online_head) //安全遍历上线 { pos2 = list_entry(p2, struct user_info, user_info_list); sprintf(newmsg->recvmsg.data, "[%s] [%s]", newmsg->recvmsg.data, pos2->user_name); } sprintf(newmsg->recvmsg.data, "%s%c", newmsg->recvmsg.data, '\n'); pr_debug("用户列表:%s\n", newmsg->recvmsg.data); //4.加入链表 list_add_tail(&newmsg->list, &udp_data_head); I_UDP++; */ break; } case UPLOAD: //上传 { struct servmsg_udp *newmsg; newmsg = (struct servmsg_udp *)malloc(sizeof(struct servmsg_udp)); /*1.填写IP与端口*/ memcpy(&(newmsg->recvmsg.self_name), msg->self_name, sizeof(msg->self_name)); //客户名 memcpy(&(newmsg->recvmsg.aim_addr_udp), &msg->aim_addr_udp, sizeof(msg->aim_addr_udp)); //IP地址与端口号 /*3.填写数据*/ char *cut_p; cut_p = strtok(msg->data, "_"); cut_p = strtok(NULL, "_"); sprintf(newmsg->recvmsg.data, "%s:%s\n", msg->self_name, cut_p); newmsg->recvmsg.data[UDP_MAXSIZE] = 0; newmsg->recvmsg.data_size = strlen(newmsg->recvmsg.data); pr_debug("UDP接收加入链表【%s】\n", cut_p); /*3.填加到链表*/ list_add_tail(&newmsg->servmsg_udp_list, &udp_data_head); I_UDP++; break; } case DOWNLOAD: //下载 { // 待续 /*1.下载列表*/ if (strncmp(msg->data, "list", 4) == 0) { //查找list struct list_head *n1 = NULL; list_for_each_safe(p1, n1, &udp_data_head) //安全遍历聊天 { pos1 = list_entry(p1, struct servmsg_udp, servmsg_udp_list); if (pos1->recvmsg.type_udp == UPLOAD) { udp_send_to(inet_ntoa(msg->aim_addr_udp.sin_addr),msg->aim_addr_udp.sin_port, \ &pos1->recvmsg, sizeof(pos1->recvmsg)); } } } char read_file(struct sockaddr_in *cin, char *way); /*2.遍历查找UPLOAD,修改接受者(不用删除下载链表)*/ if (strncmp(msg->data, "start", 5) == 0) { char *cut_p; struct sockaddr_in aim_tcp_addr;//他人信息 cut_p = strtok(msg->data, ":"); cut_p = strtok(NULL, ":"); /********************根据UDP修改客户地址********************/ aim_tcp_addr.sin_family = AF_INET; aim_tcp_addr.sin_port = msg->aim_addr_udp.sin_port; aim_tcp_addr.sin_addr.s_addr = msg->aim_addr_udp.sin_addr.s_addr; bzero(aim_tcp_addr.sin_zero, 8); /***********************************************************/ if (access(cut_p, F_OK) != 0) { read_file(&aim_tcp_addr, cut_p); } else printf("文件不存在!\n"); } break; } default: break; } return 0; } void *udp_linked_list_manage(void *arg) { sleep(2); pr_debug("UDP链表管理\n"); static int num_i=0, num_j=0; while (1) { if (num_j != J_UDP) pr_debug("** 上线:%d **\n", J_UDP); /******************************************************************** if (num_i != I_UDP || num_j != J_UDP) pr_debug("** 聊天:%d,上线:%d **\n", I_UDP, J_UDP); *********************************************************************/ num_i = I_UDP; num_j = J_UDP; //1.通过对小结构体的遍历,来获得大结构体的数据 struct list_head *n1 = NULL; list_for_each_safe(p1, n1, &udp_data_head) //安全遍历聊天 { pos1 = list_entry(p1, struct servmsg_udp, servmsg_udp_list); //2.根据类型,处理数据 // printf("类型:%d,data=%s\n", pos1->recvmsg.type_udp, pos1->recvmsg.data); switch (pos1->recvmsg.type_udp) { case LOG_IN: //登入 { //登入信息不需要处理,直接用--list命令可查看的登入者信息 break; } case OFFLINE: //下线 { //有用户下线,则直接删除登入者的链表信息 break; } case REFRESH: //列表 { //在接收线程,修改类型,通过私聊发送出 break; } case UPLOAD: //上传 { //在接收线程处理了 break; } case DOWNLOAD: //下载 { //在接收线程处理了 break; } case CHAT_ONE: //私聊 { /*提取聊天包,打印*/ if(strncmp(pos1->recvmsg.aim_name, MY_NAME, strlen(MY_NAME)) == 0) { char addr[16]; u_short port; inet_ntop(AF_INET, (void *)&(pos1->recvmsg.self_addr_udp.sin_addr.s_addr), addr, sizeof(addr)); port = ntohs(pos1->recvmsg.self_addr_udp.sin_port); pr_debug("发送者:%s,接收者:%s\n", pos1->recvmsg.self_name, pos1->recvmsg.aim_name); pr_debug("发送客户地址:%s:%d\n", addr, port); pr_debug("内容[%d字节]:%s \n", pos1->recvmsg.data_size, pos1->recvmsg.data); if (strncmp(pos1->recvmsg.data, "quit", 4) == 0) { pr_debug("[%s]结束与[%s]的聊天!\n", pos1->recvmsg.self_name, pos1->recvmsg.aim_name); } I_UDP--; list_del(&pos1->servmsg_udp_list); //处理完后删除聊天 free(pos1); } break; } case CHAT_ALL: //群聊 { /*提取聊天包,发送给目标*/ struct list_head *n2 = NULL; list_for_each_safe(p2, n2, &udp_online_head) //重新遍历上线 { pos2 = list_entry(p2, struct user_info, user_info_list); if (strncmp(pos1->recvmsg.aim_name, pos2->user_name, strlen(pos2->user_name)) == 0) {//在用户列表中,找到了 continue; } pr_debug("发送者:%s,接收者:%s\n", pos1->recvmsg.self_name, pos1->recvmsg.aim_name); char addr[16]; u_short port; inet_ntop(AF_INET, (void *)&(pos2->cli_addr_udp.sin_addr.s_addr), addr, sizeof(addr)); port = ntohs(pos2->cli_addr_udp.sin_port); pr_debug("发送客户地址:%s:%d\n", addr, port); /*截取聊天信息*/ pos1->recvmsg.data[UDP_MAXSIZE] = 0; printf("内容[%d字节]:%s \n", pos1->recvmsg.data_size, pos1->recvmsg.data); if (strncmp(pos1->recvmsg.data, "quit", 4) == 0) { pr_debug("[%s]结束群聊!\n", pos1->recvmsg.self_name); } else { port = ntohs(pos2->cli_addr_udp.sin_port); udp_send_to(inet_ntoa(pos2->cli_addr_udp.sin_addr),port, \ &pos1->recvmsg, sizeof(pos1->recvmsg)); } } I_UDP--; list_del(&pos1->servmsg_udp_list); //处理完后删除聊天 free(pos1); break; } default: break; } } } return NULL; } /*UDP接收数据*/ void *recv_udp(void *arg) { sleep(1); pr_debug("UDP接收数据\n"); struct sockaddr_in cin; //发送者信息 char ret; /*3.接收数据包*/ struct msg_udp msg; //收到他人发来的包 while (1) { ret = udp_recv_from(SELF_IP, SELF_PORT_UDP, &cin, &msg); if (ret < 0) //真正出错了 { perror("recvfrom"); continue; } else { //加入链表 udp_linked_list_add(&msg); } } return NULL; } /*UDP广播接收数据*/ void *recv_broad_udp(void *arg) { sleep(1); pr_debug("UDP广播接收数据\n"); struct sockaddr_in cin; //发送者信息 char ret; /*3.接收数据包*/ struct msg_udp msg; //收到他人发来的包 while (1) { ret = udp_broad_recv_from(BROADCAST_RECV_IP, BROADCAST_RECV_PORT_UDP, &cin, &msg); if (ret < 0) //真正出错了 { perror("recvfrom"); continue; } else { //加入链表 pr_debug("UDP广播接收数据类型:%d\n", msg.type_udp); udp_linked_list_add(&msg); } } return NULL; } /******************************************以上UDP部分******************************************************/ /******************************************各功能模块*******************************************************/ /*私聊*/ void talk(char *name, char *str) { if(!name && !str) pr_debug("私聊\n"); int ret; static char aim_name[20]; /*获取对方名字*/ struct msg_udp msg_data; if(!name) { pthread_mutex_lock(&lock1); printf("对方名字:"); ret = scanf("%s", aim_name); //对方名字 pthread_mutex_unlock(&lock1); //加入临时聊天对象 aim_name[19] = '\0'; bzero(&OTHER_UDP_ADDR, sizeof(struct sockaddr_in)); struct sockaddr_in *return_udp_addr = name_reurn_addr(1, aim_name); if(return_udp_addr) memcpy(&OTHER_UDP_ADDR, return_udp_addr, sizeof(struct sockaddr_in)); } else strcpy(aim_name, name); printf("现对话为:%s\n", aim_name); /*2.发送数据包*/ char buf[UDP_MAXSIZE+1]; bzero(buf, UDP_MAXSIZE+1); if(!str) { pthread_mutex_lock(&lock1); printf("请输入内容:\n"); ret = scanf("%s", buf); pthread_mutex_unlock(&lock1); // char *s; // fflush(stdin); // s = fgets(buf, UDP_MAXSIZE, stdin); //printf("用户[%s]输入:\n", MY_NAME); } else{ strcpy(buf, str);} buf[UDP_MAXSIZE] = 0; if (strlen(aim_name) > 0 && strlen(buf) > 0) { struct sockaddr_in *aim_udp_addr; aim_udp_addr = name_reurn_addr(1, aim_name); if (aim_udp_addr) //找到此用户,则发送;否则加入链表 { //填写数据包信息 msg_data.type_udp = CHAT_ONE; //聊天类型 strcpy(msg_data.self_name, MY_NAME); //自己名字 strcpy(msg_data.aim_name, aim_name); //目标名字 msg_data.data_size = strlen(buf); //数据大小 buf[msg_data.data_size-1] = 0; memcpy(msg_data.data, buf, msg_data.data_size); //数据 memcpy(&msg_data.self_addr_udp, &SELF_UDP_ADDR, sizeof(SELF_UDP_ADDR)); //自己地址 memcpy(&msg_data.aim_addr_udp, &pos2->cli_addr_udp, sizeof(pos2->cli_addr_udp));//目标地址 udp_addr_send_to(aim_udp_addr, &msg_data, sizeof(msg_data)); } } if (strncmp(buf, "quit", 4) == 0) { msg_data.type_udp = NO_HANDLE; //不处理类型 play(); } } /*群聊*/ void toall(void) { pr_debug("群聊\n"); char *s; struct msg_udp msg_data; /*2.发送数据包*/ char buf[UDP_MAXSIZE+1]; bzero(buf, UDP_MAXSIZE+1); fflush(stdin); s = fgets(buf, UDP_MAXSIZE, stdin); //printf("用户[%s]输入:\n", MY_NAME); buf[UDP_MAXSIZE] = 0; if (strlen(buf) >= 0) { struct list_head *n2 = NULL; list_for_each_safe(p2, n2, &udp_online_head) //安全遍历上线 { pos2 = list_entry(p2, struct user_info, user_info_list); char ip[16]; u_short port; inet_ntop(AF_INET, (void *)&(pos2->cli_addr_udp.sin_addr.s_addr), ip, sizeof(ip)); port = ntohs(pos2->cli_addr_udp.sin_port); //填写数据包信息 msg_data.type_udp = CHAT_ALL; //聊天类型 strcpy(msg_data.self_name, MY_NAME); //自己名字 strcpy(msg_data.aim_name, pos2->user_name); //目标名字 msg_data.data_size = strlen(buf); //数据大小 buf[msg_data.data_size-1] = 0; memcpy(msg_data.data, buf, msg_data.data_size); //数据 memcpy(&msg_data.self_addr_udp, &SELF_UDP_ADDR, sizeof(SELF_UDP_ADDR)); //自己地址 memcpy(&msg_data.aim_addr_udp, &pos2->cli_addr_udp, sizeof(pos2->cli_addr_udp));//目标地址 udp_send_to(ip, port, &msg_data, sizeof(msg_data)); } } if (strncmp(buf, "quit", 4) == 0) { msg_data.type_udp = NO_HANDLE; //不处理类型 play(); } } /*下线*/ void lgout(void) { int ret =-1; /*填写数据包信息*/ struct msg_udp msg_data; msg_data.type_udp = OFFLINE; //退出类型 strcpy(msg_data.self_name, MY_NAME); //自己名字 /*发送*/ ret = udp_broad_send_to(BROADCAST_SEND_IP, BROADCAST_SEND_PORT_UDP, &msg_data, sizeof(msg_data)); //广播 IF_DOWN = 0; if (ret != -1) { printf("下线成功!\n"); } } /*列表*/ void list(void) { pr_debug("列表\n"); struct servmsg_udp newmsg; struct list_head *n2 = NULL; bzero(&newmsg.recvmsg.data, UDP_MAXSIZE+1); list_for_each_safe(p2, n2, &udp_online_head) //安全遍历上线 { pos2 = list_entry(p2, struct user_info, user_info_list); if(strlen((char *)&newmsg.recvmsg.data) == 0) { sprintf(newmsg.recvmsg.data, "%s", pos2->user_name); } else { sprintf(newmsg.recvmsg.data, "%s %s", newmsg.recvmsg.data, pos2->user_name); } } sprintf(newmsg.recvmsg.data, "%s%c", newmsg.recvmsg.data, '\n'); printf("用户列表:%s\n", newmsg.recvmsg.data); } /*=====================================以下TCP部分=====================================*/ void *tcp_linked_list_manage(void *arg) { sleep(2); pr_debug("TCP链表管理\n"); int file_wrfd; static int num_i=0, num_j=0; static int sequence_i = 0; //数据顺序 size_t alto=0; while (1) { if(num_j != J_TCP) printf("** 下载:%d **\n", J_TCP); num_i = I_TCP; num_j = J_TCP; //1.通过对小结构体的遍历,来获得大结构体的数据 struct list_head *n3 = NULL; list_for_each_safe(p3, n3, &tcp_data_head) //安全遍历聊天 { pos3 = list_entry(p3, struct servmsg_tcp, servmsg_tcp_list); char pr_data1[20]; memcpy(pr_data1, pos3->recvmsg.data,19); printf("link->type:%d,data:%s\n",pos3->recvmsg.type_tcp, pr_data1); //2.根据类型,处理数据 // printf("类型:%d,data=%s\n", pos1->recvmsg.type_udp, pos1->recvmsg.data); switch (pos3->recvmsg.type_tcp) { case DOWN_IF: //是否下载 { printf("用户[%s]发来文件[%s],是否接收?(==y,==n)\n", addr_return_name(&pos3->recvmsg.self_addr_tcp), pos3->recvmsg.data); char reply; while(DOWN_IF_IN != 1) { printf("等待输入...\n"); sleep(1); } reply = DATAIN[0]; DOWN_IF_IN = 0; if (reply == 'y') { printf("同意接受文件[%s]\n", pos3->recvmsg.data); //填写资料 struct msg_tcp msg; char *aim_name = addr_return_name(&pos3->recvmsg.self_addr_tcp); if(aim_name) { msg.type_tcp = DOWN_YES; //类型 /* | | */ /* 让对方,进入下个选项 */ strcpy(msg.self_name, MY_NAME); //自己的名字 strcpy(msg.aim_name, aim_name); //目标名字 msg.data_size = strlen("*no*"); //数据大小0 ~ 65535 strcpy(msg.data, "*no*"); //数据 msg.data[TCP_MAXSIZE] = 0; memcpy(&msg.self_addr_tcp, &SELF_TCP_ADDR, sizeof(struct sockaddr_in)); //自己tcp地址 memcpy(&msg.aim_addr_tcp, &pos3->recvmsg.self_addr_tcp, sizeof(struct sockaddr_in)); //目标地址 if(tcp_addr_send_to(&pos3->recvmsg.self_addr_tcp, &msg, sizeof(msg)))//发送TCP上传信息,文件名 { printf("DOWN_YES发送成功!\n"); } else { printf("DOWN_YES发送失败!\n"); break; } } else printf("确认下载,填写资料有错\n"); I_TCP--; list_del(&pos3->servmsg_tcp_list); //处理完后删除询问 free(pos3); } break; } /*====================================================* 1.对方收到DOWN_YES, 发送DOWN_START, [等待...] 2.自己收到DOWN_START, 建立文件, 发送DOWN_READY 3.对方收到DOWN_READY, 发送DOWN_LOADING, [继续...] 4.直到发送完 *====================================================*/ case DOWN_YES: //对方收到确认,上传过来 { //读取文件,并发送 printf("收到确认,准备发送!\n"); struct sockaddr_in *cin = &pos3->recvmsg.self_addr_tcp; char *way = UP_WAY; struct msg_tcp msg; char *aim_name = addr_return_name(cin); if(aim_name) { msg.type_tcp = DOWN_START; //类型 strcpy(msg.self_name, MY_NAME); //自己的名字 strcpy(msg.aim_name, aim_name); //目标名字 memcpy(&msg.self_addr_tcp, &SELF_TCP_ADDR, sizeof(struct sockaddr_in)); //自己tcp地址 memcpy(&msg.aim_addr_tcp, cin, sizeof(struct sockaddr_in)); //目标地址 char *cut_p = NULL, *cut_q = NULL; char copy_way[UDP_MAXSIZE+1]; strcpy(copy_way, way); copy_way[UDP_MAXSIZE] = 0; cut_p = strtok(copy_way, "/"); while(cut_p){ cut_q = cut_p; cut_p = strtok(NULL, "/"); if(!cut_p) break; } msg.data_size = strlen(cut_q); //数据大小0 ~ 65535 bzero(msg.data, TCP_MAXSIZE+1); strcpy(msg.data, cut_q); //数据 msg.data[TCP_MAXSIZE] = 0; printf("%s,%s\n", cut_q,way); tcp_info_check(cin); if(tcp_addr_send_to(cin, &msg, sizeof(msg))) { printf("DOWN_START发送成功!\n"); } else { printf("DOWN_START发送失败!\n"); break; } } else { printf("read_file->aim_name 错误!\n"); break; } I_TCP--; list_del(&pos3->servmsg_tcp_list); //处理完后删除确认 free(pos3); break; } case DOWN_NO: //拒绝下载 { break; } case DOWN_START: //下载开始 { /************************开始创建文件*****************************************************************************************/ char *file_name = pos3->recvmsg.data; printf("[%s]下载开始!\n", file_name); file_wrfd = open(file_name, O_RDWR | O_CREAT | O_APPEND, 0666); struct down_info *newinfo; newinfo = (struct down_info *)malloc(sizeof(struct down_info)); //1.添加信息 strcpy(newinfo->user_name, pos3->recvmsg.self_name); //用户名字 newinfo->file_wrfd = file_wrfd; //文件fd memcpy(&newinfo->cli_addr_tcp, &pos3->recvmsg.self_addr_tcp, sizeof(struct sockaddr_in)); //客户端tcp地址 //2.加入链表 list_add_tail(&newinfo->down_info_list, &tcp_accept_head); J_TCP++; //3.收到DOWN_START,发送准备好了 struct msg_tcp msg; char *aim_name = addr_return_name(&pos3->recvmsg.self_addr_tcp); if(aim_name) { msg.type_tcp = DOWN_READY; //类型 /* | | */ /* 让对方,进入下个选项 */ strcpy(msg.self_name, MY_NAME); //自己的名字 strcpy(msg.aim_name, aim_name); //目标名字 msg.data_size = strlen("*no*"); //数据大小0 ~ 65535 strcpy(msg.data, "*no*"); //数据 msg.data[TCP_MAXSIZE] = 0; memcpy(&msg.self_addr_tcp, &SELF_TCP_ADDR, sizeof(struct sockaddr_in)); //自己tcp地址 memcpy(&msg.aim_addr_tcp, &pos3->recvmsg.self_addr_tcp, sizeof(struct sockaddr_in)); //目标地址 if(tcp_addr_send_to(&pos3->recvmsg.self_addr_tcp, &msg, sizeof(msg)))//发送TCP上传信息,文件名 { printf("DOWN_READY发送成功!\n"); } else { printf("DOWN_READY发送失败!\n"); break; } } else printf("确认下载,填写资料有错\n"); sequence_i = 0; I_TCP--; list_del(&pos3->servmsg_tcp_list); //处理完后删除开始下载 free(pos3); break; } case DOWN_READY: //继续DOWN_YES的read_file上传 { printf("收到DOWN_READY\n"); DOWN_READY_IF = 1; read_file(&pos3->recvmsg.self_addr_tcp, UP_WAY); I_TCP--; list_del(&pos3->servmsg_tcp_list); //处理完后删除开始下载 free(pos3); break; } case DOWN_LOADING: //正在下载 { printf("正在下载!\n"); char pr_data[20]; memcpy(pr_data, pos3->recvmsg.data,19); pr_debug("数据[%s]\n", pr_data); printf("接受顺序:%d, 自定顺序:%d\n", pos3->recvmsg.data_sequence, sequence_i); struct list_head *n4 = NULL; list_for_each_safe(p4, n4, &tcp_accept_head) //安全遍历聊天 { pos4 = list_entry(p4, struct down_info, down_info_list); printf("user_name:%s,self_name:%s\n", pos4->user_name, pos3->recvmsg.self_name); if (strncmp(pos4->user_name, pos3->recvmsg.self_name, strlen(pos3->recvmsg.self_name)) == 0) { printf("数据顺序:%d, 数据大小:%d\n", pos3->recvmsg.data_sequence, pos3->recvmsg.data_size); int ret; if(pos3->recvmsg.data_sequence == sequence_i) { ret = write(pos4->file_wrfd, &pos3->recvmsg.data, pos3->recvmsg.data_size); sequence_i++; alto += pos3->recvmsg.data_size; I_TCP--; list_del(&pos3->servmsg_tcp_list); //处理完后删除正在下载 free(pos3); } } } break; } case DOWN_END: //下载结束 { printf("对方发送[%s]完成!\n", pos3->recvmsg.data); printf("接收大小[%.2fk], 实际大小[%.2fk]\n", alto*1.0/1024, pos3->recvmsg.alto_size*1.0/1024); struct list_head *n4 = NULL; list_for_each_safe(p4, n4, &tcp_accept_head) //安全遍历聊天 { pos4 = list_entry(p4, struct down_info, down_info_list); if (strncmp(pos4->user_name, pos3->recvmsg.self_name, strlen(pos3->recvmsg.self_name)) == 0) { if(pos3->recvmsg.data_sequence == sequence_i) { printf("关闭文件[%d]\n", pos4->file_wrfd); close(pos4->file_wrfd); sequence_i = 0; alto = 0; I_TCP--; free(pos3); list_del(&pos3->servmsg_tcp_list); //处理完后删除下载结束 J_TCP--; list_del(&pos4->down_info_list); //删除用户 free(pos4); } } } break; } case UP_YES: //确认上传 { /* struct sockaddr_in cin; char buf[TCP_MAXSIZE+1]; tcp_addr_recv_from(&SELF_TCP_ADDR, &cin, buf); buf[TCP_MAXSIZE] = 0; char *name=addr_return_name(&cin); if(strncmp(buf, "ifdown|yes", strlen("ifdown|yes")))//ifdown|yes printf("对方[%s],同意接收,请输入2,再回车", name); else printf("对方[%s],拒绝接收,返回请 --quit,继续请重新选择", name); */ break; } case UP_NO: //拒绝上传 { break; } default: break; } } } return NULL; } /*TCP接收数据*/ void *recv_tcp(void *arg) { sleep(1); pr_debug("TCP接收数据\n"); /*5.接收数据包*/ int ret = -1 ; struct sockaddr_in cin; //发送者信息 struct msg_tcp msg; //收到他人发来的包 int tcp_addr_fd = tcp_addr_ini(&SELF_TCP_ADDR); while (1) { bzero(&msg, sizeof(msg)); if(tcp_addr_fd) { ret = tcp_addr_recv_from(tcp_addr_fd, &cin, &msg); printf("while体中recv\n"); tcp_info_check(&cin); if (ret < 0) //真正出错了 { perror("tcp_addr_recv_from"); continue; } else if(ret >0) { printf("recv->type:%d\n",msg.type_tcp); struct servmsg_tcp *newmsg; newmsg = (struct servmsg_tcp *)malloc(sizeof(struct servmsg_tcp)); //1.添加尾部 memcpy(&(newmsg->recvmsg), &msg, sizeof(msg)); //数据 //2.加入链表 list_add_tail(&newmsg->servmsg_tcp_list, &tcp_data_head); I_TCP++; } } } return NULL; } /*上传文件*/ char read_file(struct sockaddr_in *cin, char *way) { int file_rdfd; char buf[TCP_MAXSIZE+1]; int sequence_i = 0; struct msg_tcp msg; size_t size, alto, real_num=0; while(!DOWN_READY_IF) { sleep(1); printf("等待DOWN_READY回复\n"); } DOWN_READY_IF = 0; file_rdfd = open(way, O_RDONLY, 0644); alto = size = lseek(file_rdfd, 0L, SEEK_END) - lseek(file_rdfd, 0L, SEEK_SET); if (alto == 0) { pr_debug("空文件!\n"); } while (size >= TCP_MAXSIZE) //文件大于5k,则每8k上传 { bzero(buf, TCP_MAXSIZE+1); lseek(file_rdfd, 0L, real_num); if (read(file_rdfd, buf, TCP_MAXSIZE) > 0) { msg.type_tcp = DOWN_LOADING; //类型 strcpy(msg.self_name, MY_NAME); //自己的名字 char *aim_name = addr_return_name(cin); if(aim_name) strcpy(msg.aim_name, aim_name); //目标名字 msg.data_size = TCP_MAXSIZE; //数据大小0 ~ 65535 msg.data_sequence = sequence_i; bzero(msg.data, TCP_MAXSIZE+1); memcpy(msg.data, buf, TCP_MAXSIZE); //数据 msg.data[TCP_MAXSIZE] = 0; if (tcp_addr_send_to(cin, &msg, sizeof(msg))) { sequence_i++; real_num += TCP_MAXSIZE; size -= TCP_MAXSIZE; printf("上传 >5k %.2f%%\n", real_num*100.0/alto); } } else { printf("读取文件失败1\n"); } } while (size < TCP_MAXSIZE && size > 0) //小于5k,则按size大小上传 { bzero(buf, TCP_MAXSIZE+1); lseek(file_rdfd, 0L, real_num); if (read(file_rdfd, buf, size) != -1) { msg.type_tcp = DOWN_LOADING; //类型 strcpy(msg.self_name, MY_NAME); //自己的名字 char *aim_name = addr_return_name(cin); if(aim_name) strcpy(msg.aim_name, aim_name); //目标名字 msg.data_size = size; //数据大小0 ~ 65535 msg.data_sequence = sequence_i; bzero(msg.data, TCP_MAXSIZE+1); memcpy(msg.data, buf, size); //数据 msg.data[TCP_MAXSIZE] = 0; if (tcp_addr_send_to(cin, &msg, sizeof(msg))) { sequence_i++; real_num = real_num + size; size = size - size; printf("上传 <5k %.2f%%\n", real_num*100.0/alto); break; } } else { printf("读取文件失败2\n"); } } msg.type_tcp = DOWN_END; //类型 strcpy(msg.self_name, MY_NAME); //自己的名字 char *aim_name = addr_return_name(cin); if(aim_name) strcpy(msg.aim_name, aim_name); //目标名字 msg.data_size = strlen("upend"); //数据大小0 ~ 65535 msg.data_sequence = sequence_i; msg.alto_size = alto; bzero(msg.data, TCP_MAXSIZE+1); strcpy(msg.data, "upend"); //数据 msg.data[TCP_MAXSIZE] = 0; if (tcp_addr_send_to(cin, &msg, sizeof(msg))) //上传完成 { printf("上传完成!\n发送大小[%.2fk], 实际大小[%.2fk]\n", alto*1.0/1024, real_num*1.0/1024); } else printf("上传失败!\n"); close(file_rdfd); return 0; } /*上传*/ void up(void) { int ret = -1; ret = system("clear"); printf("this is UPLOAD\n"); printf("=============上传帮助=============\n"); printf("== 1.默认本目录+【文件名】 ==\n"); printf("== 2.【完整文件路径】 ==\n"); printf("== 3.查看上传文件列表 ==\n"); printf("== 4.退出 ==\n"); printf("==================================\n"); up_ord(); } void up_ord(void) { int ret = -1; char *s; char ord[10]; pthread_mutex_lock(&lock1); printf("选择命令:"); ret = scanf("%s", ord); pthread_mutex_unlock(&lock1); if (strncmp(ord, "clear", 5) == 0) { up(); } else if (!((strlen(ord) == 1) && (ord[0] == '1' || '2' || '3' || '4'))) { printf("输入选项错误,进入命令界面!\n"); play(); } else { switch (atoi(ord)) { char file_name[20]; char aim_name[20]; static struct sockaddr_in *aim_addr_udp = NULL; case 1: { pr_debug("进入选项1\n"); s = getcwd(UP_WAY, sizeof(UP_WAY)); pthread_mutex_lock(&lock1); printf("当前目录下,请输入文件名:\n"); ret = scanf("%s", file_name); pthread_mutex_unlock(&lock1); sprintf(UP_WAY,"%s/%s", UP_WAY, file_name); if (access(UP_WAY, F_OK | R_OK) == 0) { pr_debug("[%s]存在!\n", file_name); pthread_mutex_lock(&lock1); printf("接收者名字:\n"); ret = scanf("%s", aim_name); pthread_mutex_unlock(&lock1); struct sockaddr_in *aim_addr_tcp = name_reurn_addr(2, aim_name); //填写资料 struct msg_tcp msg; if(aim_addr_tcp) { msg.type_tcp = DOWN_IF; //类型 strcpy(msg.self_name, MY_NAME); //自己的名字 strcpy(msg.aim_name, aim_name); //目标名字 msg.data_size = strlen(file_name); //数据大小0 ~ 65535 strcpy(msg.data, file_name); //数据 msg.data[TCP_MAXSIZE] = 0; memcpy(&msg.self_addr_tcp, &SELF_TCP_ADDR, sizeof(struct sockaddr_in)); //自己tcp地址 memcpy(&msg.aim_addr_tcp, aim_addr_tcp, sizeof(struct sockaddr_in)); //目标地址 tcp_addr_send_to(aim_addr_tcp, &msg, sizeof(msg));//发送TCP上传信息,文件名 printf("上传请求成功!\n"); } else printf("上传,填写资料有错\n"); } break; } case 2: { pr_debug("进入选项2\n"); s = fgets(UP_WAY, sizeof(UP_WAY), stdin); if (access(UP_WAY, F_OK | R_OK) == 0) { char *cut_p; cut_p = strtok(UP_WAY, "/"); while (cut_p) { cut_p = strtok(NULL, "/"); } pr_debug("[%s]存在!\n", cut_p); char file_info[30]; sprintf(file_info, "if_down%s", cut_p); tcp_send_to(OTHER_IP, OTHER_PORT_TCP, file_info, sizeof(file_info));//发送TCP上传信息,文件名 /*填写数据包信息*/ struct msg_udp msg_data; msg_data.type_udp = UPLOAD; //聊天类型 strcpy(msg_data.self_name, MY_NAME); //自己名字 sprintf(msg_data.data, "upstart_%s", cut_p); //发送UDP上传信息,文件名 udp_send_to(OTHER_IP, OTHER_PORT_TCP, &msg_data, sizeof(msg_data));//发送UDP上传信息,文件名 if(aim_addr_udp) read_file(aim_addr_udp, UP_WAY); } break; } case 3: { pr_debug("进入选项3\n"); //发送下载列表信息 break; } case 4: { pr_debug("进入选项4\n"); play(); break; } } } } /*下载*/ void down(void) { int ret = -1; char *s; ret = system("clear"); printf("this is DOWNLOAD\n"); printf("==============下载帮助==============\n"); printf("== 1.默认本目录,为下载路径 ==\n"); printf("== 2.输入下载文件路径 ==\n"); printf("== 3.查看下载文件列表 ==\n"); printf("== 4.开始下载 ==\n"); printf("== 5.退出 ==\n"); printf("====================================\n"); char ord[10]; pthread_mutex_lock(&lock1); printf("命令:"); ret = scanf("%s", ord); pthread_mutex_unlock(&lock1); if (!((strlen(ord) == 1) && (ord[0] == '1' || '2' || '3' || '4'))) { printf("输入选项错误,进入命令界面!\n"); play(); } switch (atoi(ord)) { case 1: { pr_debug("进入选项1\n"); s = getcwd(DOWN_WAY, sizeof(DOWN_WAY)); break; } case 2: { pr_debug("进入选项2\n"); s = fgets(DOWN_WAY, sizeof(DOWN_WAY), stdin); if (access(DOWN_WAY, F_OK | R_OK) == 0) { pr_debug("目录存在,可以下载!\n"); } else { char ord[50] = "mkdir -p "; sprintf(ord, "%s%s", ord, DOWN_WAY); ret = system(DOWN_WAY); pr_debug("目录不存在,创建成功,可以下载!\n"); } break; } case 3: { pr_debug("进入选项3\n"); //发送下载列表信息 /*TCP地址信息*/ struct msg_udp usron; usron.type_udp = DOWNLOAD; //上线类型 strcpy(usron.self_name, MY_NAME); //自己名字 strcpy(usron.data, "list"); //list标识 usron.aim_addr_udp.sin_family = AF_INET; //他人地址 usron.aim_addr_udp.sin_port = htons(OTHER_PORT_UDP); //UDP接收列表 usron.aim_addr_udp.sin_addr.s_addr = inet_addr(OTHER_IP); bzero(usron.aim_addr_udp.sin_zero, 8); udp_send_to(OTHER_IP, OTHER_PORT_TCP, &usron, sizeof(usron));//发送UDP上传信息,文件名 break; } case 4: { pr_debug("进入选项4\n"); //发送下载列表信息 /*TCP地址信息*/ struct msg_udp usron; usron.type_udp = DOWNLOAD; //上线类型 strcpy(usron.self_name, MY_NAME); //自己名字 char file_name[30]; printf("请输入文件名:"); ret = scanf("%s", file_name); sprintf(usron.data, "start:%s", file_name);//start标识 usron.aim_addr_udp.sin_family = AF_INET; //他人地址 usron.aim_addr_udp.sin_port = htons(OTHER_PORT_TCP); //TCP接收文件 usron.aim_addr_udp.sin_addr.s_addr = inet_addr(OTHER_IP); bzero(usron.aim_addr_udp.sin_zero, 8); udp_send_to(OTHER_IP, OTHER_PORT_TCP, &usron, sizeof(usron));//发送UDP上传信息,文件名 break; } case 5: { pr_debug("进入选项4\n"); play(); break; } } } struct sockaddr_in *name_reurn_addr(int type, char *aim_name) { int finded_name = NO_FIND; struct list_head *n2 = NULL; list_for_each_safe(p2, n2, &udp_online_head) //安全遍历上线 { pos2 = list_entry(p2, struct user_info, user_info_list); if (strncmp(aim_name, pos2->user_name, strlen(pos2->user_name)) == 0) { finded_name = HAVE_FIND; if(type == 1) return &pos2->cli_addr_udp; else if(type == 2) return &pos2->cli_addr_tcp; else return NULL; } } if (finded_name != HAVE_FIND) //找到此用户,则发送;否则加入链表 { printf("未找到[%s]此用户\n", aim_name); return NULL; } return NULL; } char *addr_return_name(struct sockaddr_in *addr) { int finded_name = NO_FIND; struct list_head *n2 = NULL; list_for_each_safe(p2, n2, &udp_online_head) //安全遍历上线 { pos2 = list_entry(p2, struct user_info, user_info_list); if (memcmp(&pos2->cli_addr_tcp.sin_addr, &addr->sin_addr, sizeof(struct in_addr)) == 0) { finded_name = HAVE_FIND; return pos2->user_name; } } if (finded_name != HAVE_FIND) //找到此用户,则发送;否则加入链表 { char ip[16]; u_short port; inet_ntop(AF_INET, (void *)&(addr->sin_addr.s_addr), ip, sizeof(ip)); port = ntohs(addr->sin_port); printf("未找到[%s:%d]此用户\n", ip, port); return NULL; } return NULL; } /*=====================================以上TCP部分=====================================*/ /*帮助*/ void help(void) { pr_debug("帮助\n"); int ret =-1; ret = system("clear"); printf("this is Help\n"); printf("=================帮助=================\n"); printf("== 1.命令格式:“--” + “命令” ==\n"); printf("== 2.聊天时,使用quit退出聊天 ==\n"); printf("== 3.使用clear回到,命令界面 ==\n"); printf("== 4.如果ctrl+c,则下线,程序结束 ==\n"); printf("== 5.输入quit,退出帮助界面 ==\n"); printf("======================================\n"); } /*判断(命令)*/ void judge(char *ord) { if(!ord); else if (strncmp(ord, "help", 4) == 0) { help(); } else if (strncmp(ord, "clear", 5) == 0) { play(); } else if (strncmp(ord, "talk", 4) == 0) { talk(NULL, NULL); } else if (strncmp(ord, "down", 4) == 0) { down(); } else if (strncmp(ord, "list", 4) == 0) { list(); } else if (strncmp(ord, "lgout", 5) == 0) { lgout(); } else if (strncmp(ord, "toall", 5) == 0) { toall(); } else if (strncmp(ord, "up", 2) == 0) { up(); } else { printf("没有这个命令!\n"); } } /*显示*/ void play(void) { int ret = -1; ret = system("clear"); printf("this is LAN chat\n"); printf("=================命令===============\n"); printf("== --help 帮助 --lgout 下线 ==\n"); printf("== --talk 私聊 --toall 群聊 ==\n"); printf("== --down 下载 --up 上传 ==\n"); printf("== --list 列表 --clear 清屏 ==\n"); printf("====================================\n"); } /*命令 或 聊天*/ void order_or_chat(char *ord) { char ret; char *cut_p; char *aim_name; char new_ord[UDP_MAXSIZE+1]; while(IF_ORD_IN == 0); if (!ord) //为空,输入 { bzero(new_ord, UDP_MAXSIZE+1); pthread_mutex_lock(&lock1); printf("请输入命令或消息:\n"); ret = scanf("%s", new_ord); pthread_mutex_unlock(&lock1); order_or_chat(new_ord); } else if (strncmp(ord, "--", 2) == 0) //不为空,直接去掉-- { cut_p = strtok(ord, "--"); if (cut_p) { judge(cut_p); } } else if (strncmp(ord, "++", 2) == 0) //不为空,直接去掉-- { cut_p = strtok(ord, "++"); if (cut_p && cut_p[0] == 'y') { printf("cut_p:%s\n", cut_p); strcpy(DATAIN, cut_p); CHANGE_AIM_IF_IN = 1; } } else if (strncmp(ord, "==", 2) == 0) //不为空,直接去掉-- { cut_p = strtok(ord, "=="); if (cut_p && cut_p[0] == 'y') { printf("cut_p:%s\n", cut_p); strcpy(DATAIN, cut_p); DOWN_IF_IN = 1; } } else { aim_name = addr_return_name(&OTHER_UDP_ADDR); if(aim_name && ord) //找到用户 { talk(aim_name, ord); } else { send_online_info(); } } order_or_chat(NULL); } void nametrue(int argc, char *argv[]) { if (argc >= 2) { memcpy(MY_NAME, argv[1], strlen(argv[1])); //自己名字 } else { strcpy(MY_NAME, "xx"); printf("please input your name!\n"); } } void func(int signo) { lgout(); pr_debug("\n[%s]退出!\n", MY_NAME); exit(1); } /*填写本机绑定IP、端口号*/ char info_udp_tcp(void) { SELF_UDP_ADDR.sin_family = AF_INET; //自己UDP地址 SELF_UDP_ADDR.sin_port = htons(SELF_PORT_UDP); SELF_UDP_ADDR.sin_addr.s_addr = inet_addr(SELF_IP); bzero(SELF_UDP_ADDR.sin_zero, 8); SELF_TCP_ADDR.sin_family = AF_INET; //自己TCP地址 SELF_TCP_ADDR.sin_port = htons(SELF_PORT_TCP); SELF_TCP_ADDR.sin_addr.s_addr = inet_addr(SELF_IP); bzero(SELF_TCP_ADDR.sin_zero, 8); return 0; } /*登入线程*/ void *loading_thread(void *arg) { play(); //显示界面 info_udp_tcp(); //tcp udp 信息IP端口绑定 loading_udp(); //上线 sleep(3); order_or_chat(NULL); //命令判断->进入各功能 return NULL; } int main(int argc, char *argv[]) { nametrue(argc, argv); //处理输入名字 pr_debug("昵称:%s\n", MY_NAME); //测试名字 signal(SIGINT, func); //注册Ctrl + C pthread_mutex_init(&lock1, NULL); //初始化锁1 pthread_t tid1; //登入、命令处理 pthread_t tid2; //UDP接收线程,聊天 pthread_t tid3; //UDP广播接收线程,上线 pthread_t tid4; //TCP接收线程,文件传送 pthread_t tid5; //循环遍历,结构体处理,类型UDP pthread_t tid6; //循环遍历,结构体处理,类型TCP pthread_create(&tid1, NULL, loading_thread, NULL); pthread_create(&tid2, NULL, recv_udp, NULL); pthread_create(&tid3, NULL, recv_broad_udp, NULL); pthread_create(&tid4, NULL, recv_tcp, NULL); pthread_create(&tid5, NULL, udp_linked_list_manage, NULL); pthread_create(&tid6, NULL, tcp_linked_list_manage, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); pthread_join(tid3, NULL); pthread_join(tid4, NULL); pthread_join(tid5, NULL); pthread_join(tid6, NULL); return 0; }