-
-
Save jubnzv/93d7f1f3e334552fcb6cd01aedfee93b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <arpa/inet.h> | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <errno.h> | |
#include "network-api.h" | |
int main() | |
{ | |
int fd; | |
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
perror("socket"); | |
exit(EXIT_FAILURE); | |
} | |
struct sockaddr_in addr; | |
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); | |
addr.sin_port = htons(9000); | |
addr.sin_family = AF_INET; | |
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) { | |
perror("connect"); | |
exit(EXIT_FAILURE); | |
} | |
int attempts_left = 5; | |
while (--attempts_left > 0) { | |
char in_data[6]; | |
char *out_data = "test\0"; | |
printf("send\n"); | |
if (blocking_send(fd, out_data, 6) != 0) | |
break; | |
printf("recv\n"); | |
if (blocking_recv(fd, in_data, 6) != 0) | |
break; | |
printf("done (attempts left: %d)\n", attempts_left); | |
sleep(1); | |
} | |
printf("Closing socket\n"); | |
close(fd); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: | |
gcc server.c network-api.c -o server | |
gcc client.c network-api.c -o client |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <arpa/inet.h> | |
#include <stdio.h> | |
#include "network-api.h" | |
int blocking_recv(int sock, char *data, size_t size) { | |
size_t remain_data = size; | |
ssize_t recv_nb; | |
int offset = 0; | |
while ((remain_data > 0) && | |
((recv_nb = recv(sock, data + offset, remain_data, 0)) >= 0)) { | |
remain_data -= recv_nb; | |
offset += recv_nb; | |
} | |
if (recv_nb == -1 || remain_data > 0) { | |
perror("recv"); | |
return -1; | |
} | |
return 0; | |
} | |
int blocking_send(int sock, char *buf, size_t size) { | |
size_t total = 0; | |
int remain = size; | |
int n; | |
while (total < size) { | |
n = send(sock, buf + total, remain, 0); | |
if (n == -1) { | |
perror("send"); | |
break; | |
} | |
total += n; | |
remain -= n; | |
} | |
return (total == size) ? 0 : -1; | |
} | |
int set_timeout(int fd, int sec) { | |
struct timeval timeout; | |
timeout.tv_sec = sec; | |
timeout.tv_usec = 0; | |
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, | |
sizeof(timeout)) < 0) { | |
perror("setsockopt"); | |
return -1; | |
} | |
if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, | |
sizeof(timeout)) < 0) { | |
perror("setsockopt"); | |
return -1; | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef NETWORK_API_H | |
#define NETWORK_API_H | |
#include <stddef.h> | |
int blocking_recv(int sock, char *data, size_t size); | |
int blocking_send(int sock, char *buf, size_t size); | |
int set_timeout(int fd, int sec); | |
#endif // NETWORK_API_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <arpa/inet.h> | |
#include <errno.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include "network-api.h" | |
static const int data_size = 6; | |
int main() { | |
int server_fd; | |
int client_fd; | |
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
perror("socket"); | |
exit(EXIT_FAILURE); | |
} | |
int v = 1; | |
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)); | |
struct sockaddr_in saddr; | |
memset(&saddr, 0, sizeof(saddr)); | |
saddr.sin_family = AF_INET; | |
saddr.sin_addr.s_addr = INADDR_ANY; | |
saddr.sin_port = htons(9000); | |
if (bind(server_fd, (struct sockaddr *)&saddr, sizeof(saddr)) != 0) { | |
perror("bind"); | |
exit(EXIT_FAILURE); | |
} | |
if (listen(server_fd, 10) != 0) { | |
perror("listen"); | |
exit(EXIT_FAILURE); | |
} | |
while (1) { | |
struct sockaddr_in caddr; | |
size_t len = sizeof(caddr); | |
printf("Waiting for connection\n"); | |
if ((client_fd = accept(server_fd, (struct sockaddr *)&caddr, (socklen_t *)&len)) < 0) { | |
perror("accept"); | |
continue; | |
} | |
printf("Connection accepted\n"); | |
// Set the timeout using SO_{SND,RCV}TIMEO | |
if (set_timeout(client_fd, 3) != 0) { | |
continue; | |
} | |
// Send and receive data in the loop. We assume that the client is stuck, | |
// we'll break the connection using a timeout. | |
while (1) { | |
char in_data[data_size]; | |
char *out_data = "test\0"; | |
printf("recv\n"); | |
if (blocking_recv(client_fd, in_data, data_size) != 0) | |
break; | |
printf("send\n"); | |
if (blocking_send(client_fd, out_data, data_size) != 0) | |
break; | |
printf("done\n"); | |
} | |
printf("Waiting for new connection.\n"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment