int send_to_client(ChatClient *cli, const char *msg, MsgType msg_type) { ChatPacket *pkt = packet_new(SERV_NAME, cli->name); pkt->nmsg = 1; pkt->msg[0] = strdup(msg); pkt->time = gettime(); pkt->type = get_msg_type(msg_type); cli->pktsnd = pkt; return client_flush(cli); }
/** * @brief 客户端注册账号 * * @param cli 客户端 * @param user_name 用户名 * @param pwd 密码 * * @return */ int client_register(ChatClient *cli) { ChatPacket *pkt = packet_new(cli->name, SERV_NAME); pkt->nmsg = 2; pkt->msg[0] = strdup(g_cmd[CMD_REGISTER]); pkt->msg[1] = strdup(cli->password); pkt->time = gettime(); cli->pktsnd = pkt; return client_flush(cli); }
// 客户端的写协程处理过程 static void fiber_writer(user_client* client) { client->set_waiter(); client->set_waiting(true); while (true) { int mtype; // 等待消息通知 client->wait(mtype); // 从本身消息队列中提取消息并发送至本客户端 if (client_flush(client) == false) { printf("%s(%d), user: %s, flush error %s\r\n", __FUNCTION__, __LINE__, client->get_name(), acl::last_serror()); break; } #ifdef USE_CHAN if (mtype == MT_LOGOUT) { printf("%s(%d), user: %s, MT_LOGOUT\r\n", __FUNCTION__, __LINE__, client->get_name()); break; } if (mtype == MT_KICK) { printf("%s(%d), user: %s, MT_KICK\r\n", __FUNCTION__, __LINE__, client->get_name()); client->get_stream().write("You're kicked\r\n"); break; } #else if (client->exiting()) { printf("%s(%d), user: %s exiting\r\n", __FUNCTION__, __LINE__, client->get_name()); break; } #endif } client->set_waiting(false); printf(">>%s(%d), user: %s, logout\r\n", __FUNCTION__, __LINE__, client->get_name()); // 通知该客户端退出 client_logout(client); printf("-------__nwriter: %d-----\r\n", --__nwriter); }
/****************************************************************** * This function is called when an event occurs on a client socket ******************************************************************/ void client_cb(int fd, short events, void *arg) { assert(arg != NULL); Client *cli = arg; int free = 0; // g_hash_table_foreach(g_jobqueue, _print_queue, NULL); if ((events & EV_WRITE) != 0) { event_del(&cli->evt); cli->evt.ev_events = EV_READ|EV_PERSIST; event_add(&cli->evt, NULL); if (client_flush(cli) < 0) { free = 1; } } if ((events & EV_READ) != 0) { int ret = 0; if (!cli->buffer_in) { cli->buffer_in = getBlock(HEADER_SIZE); incRef(cli->buffer_in); ret = client_recv(cli, HEADER_SIZE); } if (ret >= 0) { /* Make sure we don't over-read into the next packet */ int psize = HEADER_SIZE; if (cli->buffer_in->nbytes >= HEADER_SIZE) { if (ntohl(*(uint32_t*)(cli->buffer_in->bytes + HEADER_OFFSET_MAGIC)) != MAGIC_REQUEST) { free = 1; g_warning("[%s] Invalid MAGIC", cli->id); goto free_client; } psize = HEADER_SIZE + ntohl(*(uint32_t*)(cli->buffer_in->bytes + HEADER_OFFSET_SIZE)); /* If the input block isn't large enough to receive the entire packet then switch to one that is */ if (psize > cli->buffer_in->size) { #if DEBUG g_debug("Switching to bigger block (pktsize=%d)", psize); #endif /* Create new (bigger) block */ MemBlock *block = getBlock(psize + 1); /* +1 for terminating NULL to make args easier to work with */ if (!block) { g_error("Failed to get block of size %d", psize); free = 1; goto free_client; } incRef(block); /* Copy bytes into new block */ block->nbytes = cli->buffer_in->nbytes; memmove(block->bytes, cli->buffer_in->bytes, cli->buffer_in->nbytes); /* Swap blocks */ decRef(cli->buffer_in); cli->buffer_in = block; } } int num = psize - cli->buffer_in->nbytes; if (num > 0) ret = client_recv(cli, num); } if (ret < 0) { #if DEBUG g_debug("[%s] Connection on closed", cli->id); #endif free = 1; } else if (ret >= 0) { if (process_client(cli) != 0) { g_warning("[%s] Processing of client failed", cli->id); free = 1; } } } /*if ((events & (EV_READ|EV_WRITE)) == 0) { g_warning("[%s] unhandled event %d", __func__, events); }*/ free_client: if (free != 0) { #if DEBUG g_message("[%s] Client disconnected", cli->id); #endif /*printf("[%s] Removing client %d\n", __func__, cli->fd);*/ close(cli->fd); cli->fd = -1; fail_working_jobs(cli); stop_all_listening(cli); unregister_all_abilities(cli); event_del(&cli->evt); g_ptr_array_remove_fast(g_clients, cli); client_free(cli); } }
/** * @brief 分析客户端输入的数据 * * @param cli 客户端数据结构 * @param input 输入的数据 * * @return */ int client_parse_input(ChatClient *cli, char *input) { int ret = 0; int file_flag = 0; input = str_strip(input); //去掉字符串首尾的空格 if(input == NULL) { return -1; } char *to = NULL; char *msg = NULL; ServerCmd cmd = CMD_LAST; packet_free(cli->pktsnd); //清空发送数据包 cli->pktsnd = NULL; if(strncmp("to ", input, 3) == 0) //比较前三个字符 { input += 3; if(line_parse(input, ':', &to, &msg) == 0) //以:为分隔符,将字符串分成两段 { cli->pktsnd = packet_new(cli->name, to); } } else if(strncmp("file to ", input, 8) == 0) { input += 8; if(line_parse(input, ':', &to, &msg) == 0) //以:为分隔符,将字符串分成两段 { cli->pktsnd = packet_new(cli->name, to); } file_flag = 1; } else if(strcmp(input, "whoison") == 0) { cli->pktsnd = packet_new(cli->name, SERV_NAME); cmd = CMD_WHOISON; msg = (char *) g_cmd[cmd]; } else if(strcmp(input, "showuser") == 0) { cli->pktsnd = packet_new(cli->name, SERV_NAME); cmd = CMD_SHOWUSER; msg = (char *) g_cmd[cmd]; } else if(strcmp(input, "help") == 0) { printf("\rto usr: msg --------- send msg to 'usr'\n"); printf("file to usr: filepath --------- send file to 'usr'\n"); printf("whoison --------- check server who is online\n"); printf("howuser --------- check all users who are registered\n"); printf("logout/bye/exit --------- logout and exit client\n"); return 0; } else if(strcmp(input, "logout") == 0 || strcmp(input, "exit") == 0 || strcmp(input, "bye") == 0) { cli->pktsnd = packet_new(cli->name, SERV_NAME); cmd = CMD_LOGOUT; msg = (char *) g_cmd[cmd]; } if(file_flag) { cli->pktsnd->type = get_msg_type(MSG_FILE_SEND); //设置发送的是文件类型 packet_add_msg(cli->pktsnd, msg); FILE *fp = fopen(msg, "r"); char buffer[MAXLEN]; if (fp == NULL) { printf("File: %s Not Found!\n", msg); } else { bzero(buffer, MAXLEN); while(fgets(buffer, MAXLEN, fp) != NULL) { packet_add_msg(cli->pktsnd, buffer); bzero(buffer, MAXLEN); } fclose(fp); printf("File:\t%s Transfer Finished!\n", msg); } ret = client_flush(cli); } if(msg && cli->pktsnd) { cli->pktsnd->type = get_msg_type(MSG_TEXT_SEND); //设置发送的是文字类型 packet_add_msg(cli->pktsnd, msg); ret = client_flush(cli); if(cmd==CMD_LOGOUT) { exit(0); } } return ret; }