#include #include #include #include #include #include #include #include #include const uint16_t SERVER_PORT = 1092; const int MAX_CLIENT_NUM = 20; const int MESSAGE_LEN = 256; const int HEADER_LEN = 4; int serv_sock; int clnt_socks[MAX_CLIENT_NUM]; struct sockaddr_in clnt_addrs[MAX_CLIENT_NUM]; struct message { uint8_t opcode, status; uint16_t length; char data[MESSAGE_LEN - HEADER_LEN]; }; struct client { uint16_t id, port; uint32_t addr; }; void send_message(int clnt_sock, uint8_t opcode, uint8_t status, uint16_t length, char data[]) { struct message msg; msg.opcode = opcode; msg.status = status; msg.length = htons(length); memcpy(msg.data, data, length); write(clnt_sock, &msg, MESSAGE_LEN); } void *conn(void *id) { uint16_t clnt_id = *(uint16_t *)id; int clnt_sock = clnt_socks[clnt_id]; char data[MESSAGE_LEN]; sprintf(data, "Hello, client %hu.", clnt_id); send_message(clnt_sock, 0, 1, strlen(data), data); for (;;) { struct message msg; int expect = MESSAGE_LEN; for (char *p = (char *)&msg; expect > 0;) { int len = read(clnt_sock, p, expect); if (len <= 0) { break; } expect -= len; p += len; } if (expect > 0) { break; } printf("Receive message from client %hu. opcode = %hu.\n", clnt_id, msg.opcode); switch (msg.opcode) { case 1: { time_t now; time(&now); strcpy(data, ctime(&now)); send_message(clnt_sock, 1, 1, strlen(data) - 1, data); break; } case 2: { gethostname(data, MESSAGE_LEN); send_message(clnt_sock, 2, 1, strlen(data), data); break; } case 3: { int cnt = 0; for (uint16_t i = 0; i < MAX_CLIENT_NUM; i++) { if (clnt_socks[i] != -1) { ((struct client *)data)[cnt].id = htons(i); ((struct client *)data)[cnt].addr = clnt_addrs[i].sin_addr.s_addr; ((struct client *)data)[cnt].port = clnt_addrs[i].sin_port; cnt++; } } send_message(clnt_sock, 3, 1, sizeof(struct client) * cnt, data); break; } case 4: { uint16_t id = ntohs(((uint16_t *)msg.data)[0]); if (clnt_socks[id] == -1) { send_message(clnt_sock, 4, 2, 0, NULL); } else { ((uint16_t *)msg.data)[0] = htons(clnt_id); send_message(clnt_sock, 4, 1, 0, NULL); send_message(clnt_socks[id], 0, 0, strlen(msg.data + 2) + 2, msg.data); printf(" Forward message to client %hu.\n", id); } break; } default: { sprintf(data, "Invalid operation."); send_message(clnt_sock, 0, 2, strlen(data), data); } } } close(clnt_sock); printf("Client %hu disconnected.\n", clnt_id); clnt_socks[clnt_id] = -1; return NULL; } void stop_server(int sig) { for (uint16_t i = 0; i < MAX_CLIENT_NUM; i++) { if (clnt_socks[i] != -1) { close(clnt_socks[i]); printf("Client %hu disconnected.\n", i); clnt_socks[i] = -1; } } close(serv_sock); puts("Stop listening."); exit(0); } int main() { memset(clnt_socks, -1, sizeof(clnt_socks)); serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (serv_sock == -1) { puts("Create socket failed."); exit(1); } struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(SERVER_PORT); if (bind(serv_sock, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) { puts("Bind socket failed."); exit(1); } if (listen(serv_sock, MAX_CLIENT_NUM) == -1) { puts("Listen socket failed."); exit(1); } puts("Start listening on port 1092..."); signal(SIGINT, stop_server); for (;;) { struct sockaddr_in clnt_addr; socklen_t clnt_addr_size = sizeof(clnt_addr); int clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_addr_size); if (clnt_sock == -1) { puts("Create socket failed."); continue; } for (uint16_t i = 0; i < MAX_CLIENT_NUM; i++) { if (clnt_socks[i] == -1) { clnt_socks[i] = clnt_sock; clnt_addrs[i] = clnt_addr; pthread_t pid; if (pthread_create(&pid, NULL, conn, &i) != 0) { puts("Create thread failed."); clnt_socks[i] = -1; break; } printf("Client %hu (%s:%hu) connected. pid = %lu.\n", i, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port), pid); break; } } } return 0; }