|
|
@@ -0,0 +1,148 @@
|
|
|
+#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 uint16_t MAX_CLIENT_NUM = 20;
|
|
|
+const uint16_t BUF_SIZE = 256;
|
|
|
+
|
|
|
+int serv_sock; // server socket
|
|
|
+int clnt_socks[MAX_CLIENT_NUM]; // client sockets
|
|
|
+struct sockaddr_in clnt_addrs[MAX_CLIENT_NUM]; // client addresses
|
|
|
+struct buffer
|
|
|
+{
|
|
|
+ uint16_t ptr, len;
|
|
|
+ char buf[BUF_SIZE];
|
|
|
+} clnt_buf[MAX_CLIENT_NUM]; // client buffers
|
|
|
+
|
|
|
+// get char from client socket
|
|
|
+int sgetc(uint16_t clnt_id)
|
|
|
+{
|
|
|
+ struct buffer *b = &clnt_buf[clnt_id];
|
|
|
+
|
|
|
+ if (b->ptr == b->len)
|
|
|
+ {
|
|
|
+ if (b->len == BUF_SIZE)
|
|
|
+ {
|
|
|
+ b->ptr = b->len = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ ssize_t n = read(clnt_socks[clnt_id], b->buf, BUF_SIZE - b->len);
|
|
|
+ if (n == -1)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (n == 0)
|
|
|
+ {
|
|
|
+ return -2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return b->buf[b->ptr++];
|
|
|
+}
|
|
|
+
|
|
|
+void *conn(void *id)
|
|
|
+{
|
|
|
+ uint16_t clnt_id = *(uint16_t *)id;
|
|
|
+ int clnt_sock = clnt_socks[clnt_id];
|
|
|
+
|
|
|
+ for (;;)
|
|
|
+ {
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
+}
|