Ver código fonte

First commit

Aaro Saila 1 mês atrás
commit
0fe9114117

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+build

+ 70 - 0
ch1/TCPEchoClient4.c

@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "Practical.h"
+
+int main(int argc, char **argv) {
+    if (argc < 3 || argc > 4) {
+        DieWithUserMessage("Parameter(s)", "<Server Address> <Echo Word> [<Server Port>]");
+    }
+
+    const char *server_ip = argv[1];
+    const char *echo_str = argv[2];
+    const in_port_t server_port = (argc == 4) ? atoi(argv[3]) : 7; // 7: common echo port
+
+    const int sock = socket(AF_INET, SOCK_STREAM, proto_get_num("tcp"));
+    if (sock < 0) {
+        DieWithSystemMessage("socket() failed");
+    }
+
+    struct sockaddr_in server_addr = {0};
+    server_addr.sin_family = AF_INET;
+    int ret_val = inet_pton(AF_INET, server_ip, &server_addr.sin_addr.s_addr);
+    if (ret_val == 0) {
+        DieWithUserMessage("inet_pton() failed", "invalid address string");
+    } else if (ret_val < 0) {
+        DieWithSystemMessage("inet_pton() failed");
+    }
+    server_addr.sin_port = htons(server_port);
+
+    if (connect(sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
+        DieWithSystemMessage("connect() failed");
+    }
+
+    const size_t echo_str_len = strlen(echo_str);
+
+    ssize_t num_bytes = send(sock, echo_str, echo_str_len, 0);
+    if (num_bytes < 0) {
+        DieWithSystemMessage("send() failed");
+    } else if ((size_t) num_bytes != echo_str_len) {
+        DieWithUserMessage("send()", "sent unexpected number of bytes");
+    }
+    
+    unsigned int total_bytes_rcvd = 0;
+    fputs("Received: ", stdout);
+    while (total_bytes_rcvd < echo_str_len) {
+        char buffer[BUFSIZE];
+        num_bytes = recv(sock, buffer, BUFSIZE - 1, 0);
+        if (num_bytes < 0) {
+            DieWithSystemMessage("recv() failed");
+        } else if (num_bytes == 0) {
+            DieWithUserMessage("recv()", "connection closed prematurely");
+        }
+        total_bytes_rcvd += num_bytes;
+        buffer[num_bytes] = '\0';
+        fputs(buffer, stdout);
+    }
+
+    fputc('\n', stdout);
+
+    close(sock);
+
+    return 0;
+}
+

+ 95 - 0
ch1/TCPEchoServer4.c

@@ -0,0 +1,95 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "Practical.h"
+#include "TCPServerUtility.h"
+
+static const int MAXPENDING = 5;
+
+int main(int argc, char **argv) {
+    if (argc != 2) {
+        DieWithUserMessage("Parameter(s)", "<Server Port>");
+    }
+
+    const in_port_t server_port = atoi(argv[1]);
+
+    const int server_sock = socket(AF_INET, SOCK_STREAM, proto_get_num("tcp"));
+    if (server_sock < 0) {
+        DieWithSystemMessage("socket() failed");
+    }
+
+    struct sockaddr_in server_addr = {
+        .sin_family = AF_INET,
+        .sin_addr = {
+            .s_addr = htonl(INADDR_ANY),
+        },
+        .sin_port = htons(server_port)
+    };
+
+    int ret_val = bind(
+        server_sock,
+        (struct sockaddr *) &server_addr,
+        sizeof(server_addr)
+    );
+    if (ret_val < 0) {
+        DieWithSystemMessage("bind() failed");
+    }
+
+    ret_val = listen(server_sock, MAXPENDING);
+    if (ret_val < 0) {
+        DieWithSystemMessage("listen() failed");
+    } else {
+        char server_name[INET_ADDRSTRLEN];
+        const char *ntop_res = inet_ntop(
+            AF_INET,
+            &server_addr.sin_addr.s_addr,
+            server_name,
+            sizeof(server_name)
+        );
+        if (ntop_res != NULL) {
+            printf("Listening on %s/%d...\n", server_name, server_port);
+        } else {
+            puts("Unable to get server address");
+        }
+    }
+
+    while (1) {
+        struct sockaddr_in client_addr;
+        socklen_t client_addr_len = sizeof(client_addr);
+
+        int client_sock = accept(
+            server_sock,
+            (struct sockaddr *) &client_addr,
+            &client_addr_len
+        );
+        if (client_sock < 0) {
+            DieWithSystemMessage("accept() failed");
+        }
+
+        char client_name[INET_ADDRSTRLEN];
+        const char *ntop_res = inet_ntop(
+            AF_INET,
+            &client_addr.sin_addr.s_addr,
+            client_name,
+            sizeof(client_name)
+        );
+        if (ntop_res != NULL) {
+            printf(
+                "Handling client %s/%d\n",
+                client_name,
+                ntohs(client_addr.sin_port)
+            );
+        } else {
+            puts("Unable to get client address");
+        }
+
+        HandleTCPClient(client_sock);
+    }
+
+    return 0;
+}

+ 29 - 0
ch1/TCPServerUtility.c

@@ -0,0 +1,29 @@
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "Practical.h"
+
+void HandleTCPClient(const int client_sock) {
+    char buffer[BUFSIZE];
+
+    ssize_t num_bytes_rcvd = recv(client_sock, buffer, BUFSIZE, 0);
+    if (num_bytes_rcvd < 0) {
+        DieWithSystemMessage("recv() failed");
+    }
+
+    while (num_bytes_rcvd > 0) {
+        ssize_t num_bytes_sent = send(client_sock, buffer, num_bytes_rcvd, 0);
+        if (num_bytes_sent < 0) {
+            DieWithSystemMessage("send() failed");
+        } else if (num_bytes_sent != num_bytes_rcvd) {
+            DieWithUserMessage("send()", "sent unexpected number of bytes");
+        }
+
+        num_bytes_rcvd = recv(client_sock, buffer, BUFSIZE, 0);
+        if (num_bytes_rcvd < 0) {
+            DieWithSystemMessage("recv() failed");
+        }
+    }
+
+    close(client_sock);
+}

+ 3 - 0
ch1/TCPServerUtility.h

@@ -0,0 +1,3 @@
+#pragma once
+
+void HandleTCPClient(const int client_sock);

+ 20 - 0
ch1/meson.build

@@ -0,0 +1,20 @@
+executable(
+  'client',
+  'TCPEchoClient4.c',
+  common_src,
+  include_directories: [
+    common_include
+  ],
+  c_args: c_args
+)
+
+executable(
+  'server',
+  'TCPEchoServer4.c',
+  'TCPServerUtility.c',
+  common_src,
+  include_directories: [
+    common_include
+  ],
+  c_args: c_args
+)

+ 16 - 0
common/DieWithMessage.c

@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void DieWithUserMessage(const char *msg, const char *detail) {
+    fputs(msg, stderr);
+    fputs(": ", stderr);
+    fputs(detail, stderr);
+    fputc('\n', stderr);
+    exit(1);
+}
+
+void DieWithSystemMessage(const char *msg) {
+    perror(msg);
+    exit(1);
+}
+

+ 12 - 0
common/Practical.c

@@ -0,0 +1,12 @@
+#include <netdb.h>
+#include <stddef.h>
+
+#include "Practical.h"
+
+int proto_get_num(const char *name) {
+    struct protoent *protoent = getprotobyname(name);
+    if (protoent == NULL) {
+        DieWithSystemMessage("getprotobyname");
+    }
+    return protoent->p_proto;
+}

+ 7 - 0
common/Practical.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#define BUFSIZE 512
+
+void DieWithUserMessage(const char *msg, const char *detail);
+void DieWithSystemMessage(const char *msg);
+int proto_get_num(const char *name);

+ 25 - 0
meson.build

@@ -0,0 +1,25 @@
+project(
+  'tcp-ip-sockets-in-c',
+  'c',
+  default_options: [
+    'buildtype=debug'
+  ],
+)
+
+c_args = [
+  '-std=c99',
+  '-Wall',
+  '-Wextra',
+  '-pedantic'
+]
+
+common_src = files(
+  'common/DieWithMessage.c',
+  'common/Practical.c',
+)
+
+common_include = [
+  include_directories('common')
+]
+
+subdir('ch1')