diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e56e04 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..170576d --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +CC=gcc +CC_OPTIONS=-shared-libgcc + +CLIENT_SOURCE=src/client.c +SERVER_SOURCE=src/server.c src/myutil.c + +.PHONY: all +all: bin/client bin/server + +.PHONY: clean +clean: + rm -r bin + +bin/client: $(CLIENT_SOURCE) + [[ -d bin ]] || mkdir bin + $(CC) $(CC_OPTIONS) -o bin/client $(CLIENT_SOURCE) + +bin/server: $(SERVER_SOURCE) + [[ -d bin ]] || mkdir bin + $(CC) $(CC_OPTIONS) -o bin/server $(SERVER_SOURCE) diff --git a/README b/README new file mode 100644 index 0000000..5eb8c0d --- /dev/null +++ b/README @@ -0,0 +1,36 @@ +# Test Buffer For Udp + +This project is used to test if there is a buffer for udp. Let's assume packet +A and B are sent orderly in the same time, the receiver can still read A after +B already arrive, then we think the buffer for udp is exists. + +## Program behavier + +Server listen on port 23333, receive 1 packet, then sleep for 1 second, +and receive the remain 2 packets, then exit. + +Client send 3 packet to 127.0.0.1:23333 without delay. + +## Expected result + +The expected result is server receive the frst packet at the moment the client +launch, then 1 second later, the server receive the remain 2 packets with no +interval. And the client launch and exit in a very short time. + +## Run the program + +To run the program, first build the program + + make + +then launch server + + ./bin/server + +then launch client in another terminal + + ./bin/client + +Or if you want one line command + + make ; ./bin/server & ; pid=$! ; ./bin/client ; wait $pid diff --git a/src/client.c b/src/client.c new file mode 100644 index 0000000..06a5e87 --- /dev/null +++ b/src/client.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() { + struct addrinfo hints; + struct addrinfo * result; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = 0; + hints.ai_flags = AI_PASSIVE; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + int err = getaddrinfo("127.0.0.1", "23333", &hints, &result); + if (err != 0) { + fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(err)); + exit(EXIT_FAILURE); + } + + int sock_fd; + struct addrinfo * i; + for (i = result; i != NULL; i = i->ai_next) { + sock_fd = socket(i->ai_family, i->ai_socktype, i->ai_protocol); + if (sock_fd == -1) + continue; + + if (connect(sock_fd, i->ai_addr, i->ai_addrlen) != -1) + break; + + close(sock_fd); + } + + freeaddrinfo(result); + + if (i == NULL) { + fprintf(stderr, "Could not connect\n"); + exit(EXIT_FAILURE); + } + + char x = 1; + send(sock_fd, &x, 1, 0); x++; + send(sock_fd, &x, 1, 0); x++; + send(sock_fd, &x, 1, 0); x++; + + close(sock_fd); + + return EXIT_SUCCESS; +} diff --git a/src/myutil.c b/src/myutil.c new file mode 100644 index 0000000..acbf095 --- /dev/null +++ b/src/myutil.c @@ -0,0 +1,10 @@ +#include "myutil.h" +#include + +void print_buffer(FILE * stream, const char *const buffer, size_t len) { + for (size_t i = 0; i < len; i++) { + if (i != 0) + fprintf(stream, " "); + fprintf(stream, "%2x", buffer[i]); + } +} diff --git a/src/myutil.h b/src/myutil.h new file mode 100644 index 0000000..43afedc --- /dev/null +++ b/src/myutil.h @@ -0,0 +1,3 @@ +#include + +void print_buffer(FILE* stream, char const * const buffer, size_t len); diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..ab75310 --- /dev/null +++ b/src/server.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +#include +#include "myutil.h" + +int main() { + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = 0; + hints.ai_flags = AI_PASSIVE; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + struct addrinfo *result; + int err = getaddrinfo(NULL, "23333", &hints, &result); + if (err != 0) { + fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(err)); + exit(EXIT_FAILURE); + } + + int sock_fd; + struct addrinfo * i; + for (i = result; i != NULL; i = i->ai_next) { + sock_fd = socket(i->ai_family, i->ai_socktype, i->ai_protocol); + if (sock_fd == -1) + continue; + + if (bind(sock_fd, i->ai_addr, i->ai_addrlen) == 0) + break; + } + + freeaddrinfo(result); + + if (i == NULL) { + fprintf(stderr, "Could not bind\n"); + exit(EXIT_FAILURE); + } + + size_t BUF_SIZE = 1024; + char buffer[BUF_SIZE]; + struct sockaddr_storage peer_addr; + socklen_t peer_addr_len = sizeof(struct sockaddr_storage); + + for (int i = 0; i < 3; i++) { + if (i == 1) + sleep(1); + ssize_t nread = recvfrom( + sock_fd, buffer, BUF_SIZE, 0, (struct sockaddr *)&peer_addr, &peer_addr_len + ); + + fprintf(stdout, "read %ld bytes: ", nread); + print_buffer(stdout, buffer, nread); + fprintf(stdout, "\n"); + } + + return EXIT_SUCCESS; +}