-
Notifications
You must be signed in to change notification settings - Fork 0
エコーサーバー・クライアントの実装(追加機能) #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
947bce1
51e3ec6
c7bf378
bf46092
1835e32
cb52c2f
f5f3534
36f673c
c0af539
e63117e
71f16b2
6d6bd01
1aa9a74
d726454
3b1365d
3554dc5
435b1d0
43d73ed
388a516
1667b66
a4982b7
4dc05d0
f333a30
fabe42c
0504445
94607c9
78d925d
adcb7f9
a6865bf
506020c
8d4013a
1e1e22e
442fe0a
03074e4
634519e
ccf3478
2e313ca
1632d0f
0232176
f7f6b1f
9f70e15
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,3 +2,4 @@ | |
| a.out | ||
| client | ||
| server | ||
| *.o | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,18 @@ | ||
| .PHONY: build-server | ||
| build-server: | ||
| gcc -Wall -Wextra -Wpedantic server.c -o server | ||
| CC = gcc | ||
| CFLAGS = -Wall -Wextra -Wpedantic -O2 | ||
|
|
||
| .PHONY: run-server | ||
| run-server: build-server | ||
| ./server | ||
| .PHONY: all clean | ||
|
|
||
| .PHONY: build-client | ||
| build-client: | ||
| gcc -Wall -Wextra -Wpedantic client.c -o client | ||
| all: server client | ||
|
|
||
| .PHONY: run-client | ||
| run-client:build-client | ||
| ./client | ||
| server: server.o utils.o | ||
| $(CC) $(CFLAGS) -o server server.o utils.o | ||
|
|
||
| client: client.o utils.o | ||
| $(CC) $(CFLAGS) -o client client.o utils.o | ||
|
|
||
| %.o: %.c | ||
| $(CC) $(CFLAGS) -c $< | ||
|
|
||
| clean: | ||
| rm -f server client *.o | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,52 +1,196 @@ | ||
| #include <arpa/inet.h> | ||
| #include <netinet/in.h> | ||
| #include <errno.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <sys/socket.h> | ||
| #include <unistd.h> | ||
|
|
||
| #include "utils.h" | ||
|
|
||
| #define BUFFER_SIZE 256 | ||
|
|
||
| int create_connected_socket(const char *ip, const char *port); | ||
|
|
||
| int main(int argc, char **argv) | ||
| { | ||
| int sock; | ||
| if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) | ||
| // Check if the IP address and port number are provided | ||
| if (argc != 3) | ||
| { | ||
| perror("client: socket()"); | ||
| printf("Usage: %s <ip> <port>\n", argv[0]); | ||
| exit(1); | ||
| } | ||
|
|
||
| struct sockaddr_in server_addr; | ||
| server_addr.sin_family = PF_INET; | ||
| server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); | ||
| server_addr.sin_port = htons(8080); | ||
| if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) | ||
| // Create a connected socket | ||
| int socket_fd; | ||
| if ((socket_fd = create_connected_socket(argv[1], argv[2])) == -1) | ||
| { | ||
| perror("client: connect()"); | ||
| close(sock); | ||
| puts("Failed to create a connected socket\n"); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. perror は stderr に表示されるので、合わせてこれも stderr に出力した方が良いと思います。 |
||
| exit(1); | ||
| } | ||
|
|
||
| char buf[256]; | ||
| fgets(buf, sizeof(buf), stdin); // Null-terminate the string | ||
| while (1) | ||
| { | ||
| char buf[BUFFER_SIZE]; | ||
| if (fgets(buf, BUFFER_SIZE, stdin) == NULL) | ||
| { | ||
| // Check if fgets() reached EOF | ||
| if (feof(stdin)) | ||
| { | ||
| puts("EOF detected\n"); | ||
| break; | ||
| } | ||
| else | ||
| { | ||
| perror("client: fgets()"); | ||
| close_with_retry(socket_fd); | ||
| exit(1); | ||
| } | ||
| } | ||
|
|
||
| size_t len = strlen(buf); | ||
| if (send(sock, buf, len, 0) == -1) | ||
| // Send the input to the server | ||
| size_t bytes_read = strlen(buf); | ||
| size_t total_sent = 0; | ||
| while (total_sent < bytes_read) | ||
| { | ||
| ssize_t sent_bytes = send(socket_fd, buf + total_sent, bytes_read - total_sent, 0); | ||
| if (sent_bytes == -1) | ||
| { | ||
| if (errno == EINTR) | ||
| { | ||
| continue; | ||
| } | ||
| perror("client: send()"); | ||
| close_with_retry(socket_fd); | ||
| exit(1); | ||
| } | ||
| total_sent += sent_bytes; | ||
| } | ||
|
thonda28 marked this conversation as resolved.
|
||
|
|
||
| // Receive the response from the server | ||
| size_t total_received = 0; | ||
| while (total_received < bytes_read) | ||
| { | ||
| ssize_t received_bytes = recv(socket_fd, buf + total_received, bytes_read - total_received, 0); | ||
| if (received_bytes == -1) | ||
| { | ||
| if (errno == EINTR) | ||
| { | ||
| continue; | ||
| } | ||
| perror("client: recv()"); | ||
| close_with_retry(socket_fd); | ||
| exit(1); | ||
| } | ||
| else if (received_bytes == 0) | ||
| { | ||
| puts("Connection closed by server\n"); | ||
| close_with_retry(socket_fd); | ||
| exit(1); | ||
| } | ||
| total_received += received_bytes; | ||
| } | ||
|
|
||
| // Print the received data | ||
| if (fwrite(buf, 1, total_received, stdout) != total_received) | ||
| { | ||
| perror("client: fwrite()"); | ||
| close_with_retry(socket_fd); | ||
| exit(1); | ||
| } | ||
| } | ||
|
|
||
| close_with_retry(socket_fd); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Create a connected socket to the specified IP address and port. | ||
| * | ||
| * This function creates a socket, connects it to the specified IP address and port, | ||
| * and returns the connected socket file descriptor. | ||
| * | ||
| * @param[in] ip The IP address to connect to. | ||
| * @param[in] port The port number to connect to. | ||
| * @return The file descriptor of the connected socket. | ||
| * @retval -1 An error occurred during the process. | ||
| */ | ||
| int create_connected_socket(const char *ip, const char *port_str) | ||
| { | ||
| // Parse the IP address | ||
| struct sockaddr_in server_addr4; | ||
| struct sockaddr_in6 server_addr6; | ||
| memset(&server_addr4, 0, sizeof(server_addr4)); | ||
| memset(&server_addr6, 0, sizeof(server_addr6)); | ||
| int is_ipv4 = inet_pton(PF_INET, ip, &server_addr4.sin_addr); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is_xxxxx という名前は true or false を連想させるので違う名前にしたい。 (そのままif 文で評価して -1 を true 扱いしてしまう事故が発生しそう) |
||
| int is_ipv6 = inet_pton(PF_INET6, ip, &server_addr6.sin6_addr); | ||
| if (is_ipv4 <= 0 && is_ipv6 <= 0) | ||
| { | ||
| perror("client: send()"); | ||
| close(sock); | ||
| exit(1); | ||
| printf("Invalid IP address: %s\n", ip); | ||
| return -1; | ||
| } | ||
|
|
||
| if (recv(sock, buf, sizeof(buf) - 1, 0) == -1) | ||
| // Parse the port number | ||
| int port; | ||
| if ((port = parse_port(port_str)) == -1) | ||
| { | ||
| perror("client: recv()"); | ||
| close(sock); | ||
| exit(1); | ||
| printf("Invalid port number: %s\n", port_str); | ||
| return -1; | ||
| } | ||
|
|
||
| printf("%s", buf); | ||
| // Create a socket and connect to the server | ||
| int socket_fd; | ||
| if (is_ipv4 == 1) | ||
| { | ||
| if ((socket_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. パラメータが違う同じコードが2か所(v4/v6)にあるので、共通化したい。 |
||
| { | ||
| perror("client: socket()"); | ||
| return -1; | ||
| } | ||
|
|
||
| close(sock); | ||
| server_addr4.sin_family = PF_INET; | ||
| server_addr4.sin_port = htons(port); | ||
|
|
||
| return 0; | ||
| while (connect(socket_fd, (struct sockaddr *)&server_addr4, sizeof(server_addr4)) == -1) | ||
| { | ||
| if (errno == EINTR) | ||
| { | ||
| continue; | ||
| } | ||
| perror("client: connect() using IPv4"); | ||
| close_with_retry(socket_fd); | ||
| return -1; | ||
| } | ||
| } | ||
| else if (is_ipv6 == 1) | ||
| { | ||
| if ((socket_fd = socket(PF_INET6, SOCK_STREAM, 0)) == -1) | ||
| { | ||
| perror("client: socket() using IPv6"); | ||
| return -1; | ||
| } | ||
|
|
||
| server_addr6.sin6_family = PF_INET6; | ||
| server_addr6.sin6_port = htons(port); | ||
|
|
||
| while (connect(socket_fd, (struct sockaddr *)&server_addr6, sizeof(server_addr6)) == -1) | ||
| { | ||
| if (errno == EINTR) | ||
| { | ||
| continue; | ||
| } | ||
| perror("client: connect() using IPv6"); | ||
| close_with_retry(socket_fd); | ||
| return -1; | ||
| } | ||
| } | ||
| else | ||
| { | ||
| puts("Reached the unreachable"); | ||
| return -1; | ||
| } | ||
|
|
||
| printf("Connected to %s, %d\n", ip, port); | ||
| return socket_fd; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$@
$^
という変数もあります