From 7f7c16cd407a2c9711c78f6e0bfeb58c9ae24e8c Mon Sep 17 00:00:00 2001 From: Remzi Arpaci-Dusseau Date: Thu, 30 May 2019 12:32:20 -0500 Subject: [PATCH] dist intro client/server code --- dist-intro/Makefile | 20 +++++++++++++ dist-intro/README.md | 17 +++++++++++ dist-intro/client.c | 28 ++++++++++++++++++ dist-intro/server.c | 28 ++++++++++++++++++ dist-intro/udp.c | 67 ++++++++++++++++++++++++++++++++++++++++++++ dist-intro/udp.h | 39 ++++++++++++++++++++++++++ 6 files changed, 199 insertions(+) create mode 100644 dist-intro/Makefile create mode 100644 dist-intro/README.md create mode 100644 dist-intro/client.c create mode 100644 dist-intro/server.c create mode 100644 dist-intro/udp.c create mode 100644 dist-intro/udp.h diff --git a/dist-intro/Makefile b/dist-intro/Makefile new file mode 100644 index 0000000..2401288 --- /dev/null +++ b/dist-intro/Makefile @@ -0,0 +1,20 @@ +CC := gcc +CFLAGS := -Wall -Werror + +SRCS := client.c \ + server.c + +OBJS := ${SRCS:c=o} +PROGS := ${SRCS:.c=} + +.PHONY: all +all: ${PROGS} + +${PROGS} : % : %.o Makefile + ${CC} $< -o $@ udp.c + +clean: + rm -f ${PROGS} ${OBJS} + +%.o: %.c Makefile + ${CC} ${CFLAGS} -c $< diff --git a/dist-intro/README.md b/dist-intro/README.md new file mode 100644 index 0000000..0f52a56 --- /dev/null +++ b/dist-intro/README.md @@ -0,0 +1,17 @@ + +# Distributed Systems: Introduction + +A simple UDP client and server: +- `client.c`: example client code, sends a message to the server and waits for a reply +- `server.c`: example server code, waits for messages indefinitely and replies + +Both use `udp.c` as a simple UDP communication library. + +The `Makefile` builds `client` and `server` executables. Type `make` to do this. + +To run: type `server &` to run the server in the background; then type `client` to +run the client. You will likely then want to kill the server if you are done. + +If you want to run these on different machines, you'll have to change the client +to send messages to the machine the server is running upon, instead of `localhost`. + diff --git a/dist-intro/client.c b/dist-intro/client.c new file mode 100644 index 0000000..be7a006 --- /dev/null +++ b/dist-intro/client.c @@ -0,0 +1,28 @@ +#include +#include "udp.h" + +#define BUFFER_SIZE (1000) + +// client code +int main(int argc, char *argv[]) { + struct sockaddr_in addrSnd, addrRcv; + + int sd = UDP_Open(20000); + int rc = UDP_FillSockAddr(&addrSnd, "localhost", 10000); + + char message[BUFFER_SIZE]; + sprintf(message, "hello world"); + + printf("client:: send message [%s]\n", message); + rc = UDP_Write(sd, &addrSnd, message, BUFFER_SIZE); + if (rc < 0) { + printf("client:: failed to send\n"); + exit(1); + } + + printf("client:: wait for reply...\n"); + rc = UDP_Read(sd, &addrRcv, message, BUFFER_SIZE); + printf("client:: got reply [size:%d contents:(%s)\n", rc, message); + return 0; +} + diff --git a/dist-intro/server.c b/dist-intro/server.c new file mode 100644 index 0000000..faea098 --- /dev/null +++ b/dist-intro/server.c @@ -0,0 +1,28 @@ +#include +#include "udp.h" + +#define BUFFER_SIZE (1000) + +// server code +int main(int argc, char *argv[]) { + int sd = UDP_Open(10000); + assert(sd > -1); + while (1) { + struct sockaddr_in addr; + char message[BUFFER_SIZE]; + printf("server:: waiting...\n"); + int rc = UDP_Read(sd, &addr, message, BUFFER_SIZE); + printf("server:: read message [size:%d contents:(%s)]\n", rc, message); + if (rc > 0) { + char reply[BUFFER_SIZE]; + sprintf(reply, "goodbye world"); + rc = UDP_Write(sd, &addr, reply, BUFFER_SIZE); + printf("server:: reply\n"); + } + } + return 0; +} + + + + diff --git a/dist-intro/udp.c b/dist-intro/udp.c new file mode 100644 index 0000000..a54bab1 --- /dev/null +++ b/dist-intro/udp.c @@ -0,0 +1,67 @@ +#include "udp.h" + +// create a socket and bind it to a port on the current machine +// used to listen for incoming packets +int UDP_Open(int port) { + int fd; + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + perror("socket"); + return 0; + } + + // set up the bind + struct sockaddr_in my_addr; + bzero(&my_addr, sizeof(my_addr)); + + my_addr.sin_family = AF_INET; + my_addr.sin_port = htons(port); + my_addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(fd, (struct sockaddr *) &my_addr, sizeof(my_addr)) == -1) { + perror("bind"); + close(fd); + return -1; + } + + return fd; +} + +// fill sockaddr_in struct with proper goodies +int UDP_FillSockAddr(struct sockaddr_in *addr, char *hostname, int port) { + bzero(addr, sizeof(struct sockaddr_in)); + if (hostname == NULL) { + return 0; // it's OK just to clear the address + } + + addr->sin_family = AF_INET; // host byte order + addr->sin_port = htons(port); // short, network byte order + + struct in_addr *in_addr; + struct hostent *host_entry; + if ((host_entry = gethostbyname(hostname)) == NULL) { + perror("gethostbyname"); + return -1; + } + in_addr = (struct in_addr *) host_entry->h_addr; + addr->sin_addr = *in_addr; + + return 0; +} + +int UDP_Write(int fd, struct sockaddr_in *addr, char *buffer, int n) { + int addr_len = sizeof(struct sockaddr_in); + int rc = sendto(fd, buffer, n, 0, (struct sockaddr *) addr, addr_len); + return rc; +} + +int UDP_Read(int fd, struct sockaddr_in *addr, char *buffer, int n) { + int len = sizeof(struct sockaddr_in); + int rc = recvfrom(fd, buffer, n, 0, (struct sockaddr *) addr, (socklen_t *) &len); + // assert(len == sizeof(struct sockaddr_in)); + return rc; +} + +int UDP_Close(int fd) { + return close(fd); +} + diff --git a/dist-intro/udp.h b/dist-intro/udp.h new file mode 100644 index 0000000..ccbff49 --- /dev/null +++ b/dist-intro/udp.h @@ -0,0 +1,39 @@ +#ifndef __UDP_h__ +#define __UDP_h__ + +// +// includes +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +// +// prototypes +// + +int UDP_Open(int port); +int UDP_Close(int fd); + +int UDP_Read(int fd, struct sockaddr_in *addr, char *buffer, int n); +int UDP_Write(int fd, struct sockaddr_in *addr, char *buffer, int n); + +int UDP_FillSockAddr(struct sockaddr_in *addr, char *hostName, int port); + +#endif // __UDP_h__ +