Ver Fonte

add: lab7 server

RegMs If há 4 anos atrás
pai
commit
4534877563
2 ficheiros alterados com 224 adições e 0 exclusões
  1. BIN
      lab7/server
  2. 224 0
      lab7/server.c

BIN
lab7/server


+ 224 - 0
lab7/server.c

@@ -0,0 +1,224 @@
+#include <time.h>
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+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;
+}