diff options
author | sotech117 <michael_foiani@brown.edu> | 2023-09-14 16:14:15 -0400 |
---|---|---|
committer | sotech117 <michael_foiani@brown.edu> | 2023-09-14 16:14:15 -0400 |
commit | 6eb71f25820d1ea1a050b4847338f2300734affd (patch) | |
tree | b9a42e53bcbb1f67d93a291be85adfb6754ec11c | |
parent | d9303149cb989e7af96b3964cf34018f295ba312 (diff) |
good starting point, finished the guide
-rw-r--r-- | .vscode/c_cpp_properties.json | 19 | ||||
-rw-r--r-- | Makefile | 13 | ||||
-rwxr-xr-x | client | bin | 0 -> 34200 bytes | |||
-rw-r--r-- | client.c | 100 | ||||
-rw-r--r-- | client.dSYM/Contents/Info.plist | 20 | ||||
-rw-r--r-- | client.dSYM/Contents/Resources/DWARF/client | bin | 0 -> 11222 bytes | |||
-rw-r--r-- | listener.c | 95 | ||||
-rw-r--r-- | reference.c | 72 | ||||
-rwxr-xr-x | server | bin | 0 -> 34656 bytes | |||
-rw-r--r-- | server.c | 144 | ||||
-rw-r--r-- | server.dSYM/Contents/Info.plist | 20 | ||||
-rw-r--r-- | server.dSYM/Contents/Resources/DWARF/server | bin | 0 -> 12990 bytes | |||
-rw-r--r-- | talker.c | 67 |
13 files changed, 550 insertions, 0 deletions
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..9a0a2f5 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,19 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "macFrameworkPath": [ + "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks" + ], + "compilerPath": "/usr/bin/clang", + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "macos-clang-arm64" + } + ], + "version": 4 +}
\ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5e808ed --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +CC = gcc +CFLAGS = -std=c99 -target x86_64-apple-darwin20 -g +RM = rm -f + +default: all + +all: server client + +server: server.c + $(CC) $(CFLAGS) -o server server.c + +client: client.c + $(CC) $(CFLAGS) -o client client.c
\ No newline at end of file Binary files differdiff --git a/client.c b/client.c new file mode 100644 index 0000000..591d030 --- /dev/null +++ b/client.c @@ -0,0 +1,100 @@ +/* +** client.c -- a stream socket client demo +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <netdb.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> + +#include <arpa/inet.h> + +#define PORT "3490" // the port client will be connecting to + +#define MAXDATASIZE 100 // max number of bytes we can get at once + +// get sockaddr, IPv4 or IPv6: +void *get_in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + +int main(int argc, char *argv[]) +{ + int sockfd, numbytesrecv, numbytessent; + char buf[MAXDATASIZE]; + struct addrinfo hints, *servinfo, *p; + int rv; + char s[INET6_ADDRSTRLEN]; + + if (argc != 3) { + fprintf(stderr,"usage: client hostname\n"); + exit(1); + } + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; // only IPv4 + hints.ai_socktype = SOCK_STREAM; + + if ((rv = getaddrinfo(argv[2], PORT, &hints, &servinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return 1; + } + + // loop through all the results and connect to the first we can + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + perror("client: socket"); + continue; + } + + if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd); + perror("client: connect"); + continue; + } + + break; + } + + if (p == NULL) { + fprintf(stderr, "client: failed to connect\n"); + return 2; + } + + inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), + s, sizeof s); + printf("client: connecting to %s\n", s); + + freeaddrinfo(servinfo); // all done with this structure + + if ((numbytesrecv = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) { + perror("recv"); + exit(1); + } + + buf[numbytesrecv] = '\0'; + + printf("client: received '%s'\n",buf); + + if ((numbytessent = send(sockfd, "Welcome", 7, 0)) == -1) { + perror("send"); + exit(1); + } + + buf[numbytessent] = '\0'; + + close(sockfd); + + return 0; +}
\ No newline at end of file diff --git a/client.dSYM/Contents/Info.plist b/client.dSYM/Contents/Info.plist new file mode 100644 index 0000000..d550748 --- /dev/null +++ b/client.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> + <dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleIdentifier</key> + <string>com.apple.xcode.dsym.client</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundlePackageType</key> + <string>dSYM</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>1</string> + </dict> +</plist> diff --git a/client.dSYM/Contents/Resources/DWARF/client b/client.dSYM/Contents/Resources/DWARF/client Binary files differnew file mode 100644 index 0000000..4d642ff --- /dev/null +++ b/client.dSYM/Contents/Resources/DWARF/client diff --git a/listener.c b/listener.c new file mode 100644 index 0000000..723cb1b --- /dev/null +++ b/listener.c @@ -0,0 +1,95 @@ +/* +** listener.c -- a datagram sockets "server" demo +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#define MYPORT "4950" // the port users will be connecting to + +#define MAXBUFLEN 100 + +// get sockaddr, IPv4 or IPv6: +void *get_in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + +int main(void) +{ + int sockfd; + struct addrinfo hints, *servinfo, *p; + int rv; + int numbytes; + struct sockaddr_storage their_addr; + char buf[MAXBUFLEN]; + socklen_t addr_len; + char s[INET6_ADDRSTRLEN]; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET6; // set to AF_INET to use IPv4 + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; // use my IP + + if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return 1; + } + + // loop through all the results and bind to the first we can + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + perror("listener: socket"); + continue; + } + + if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd); + perror("listener: bind"); + continue; + } + + break; + } + + if (p == NULL) { + fprintf(stderr, "listener: failed to bind socket\n"); + return 2; + } + + freeaddrinfo(servinfo); + + printf("listener: waiting to recvfrom...\n"); + + addr_len = sizeof their_addr; + if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0, + (struct sockaddr *)&their_addr, &addr_len)) == -1) { + perror("recvfrom"); + exit(1); + } + + printf("listener: got packet from %s\n", + inet_ntop(their_addr.ss_family, + get_in_addr((struct sockaddr *)&their_addr), + s, sizeof s)); + printf("listener: packet is %d bytes long\n", numbytes); + buf[numbytes] = '\0'; + printf("listener: packet contains \"%s\"\n", buf); + + close(sockfd); + + return 0; +} diff --git a/reference.c b/reference.c new file mode 100644 index 0000000..1f5b74b --- /dev/null +++ b/reference.c @@ -0,0 +1,72 @@ +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <netinet/in.h> + +struct addrinfo { + int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc. + int ai_family; // AF_INET, AF_INET6, AF_UNSPEC + int ai_socktype; // SOCK_STREAM, SOCK_DGRAM + int ai_protocol; // use 0 for "any" + size_t ai_addrlen; // size of ai_addr in bytes + struct sockaddr *ai_addr; // struct sockaddr_in or _in6 + char *ai_canonname; // full canonical hostname + + struct addrinfo *ai_next; // linked list, next node +}; + +struct sockaddr { + unsigned short sa_family; // address family, AF_xxx + char sa_data[14]; // 14 bytes of protocol address +}; + +struct sockaddr_in { + short int sin_family; // Address family, AF_INET + unsigned short int sin_port; // Port number + struct in_addr sin_addr; // Internet address + unsigned char sin_zero[8]; // Same size as struct sockaddr +}; + +// (IPv4 only--see struct in6_addr for IPv6) +// Internet address (a structure for historical reasons) +struct in_addr { + uint32_t s_addr; // that's a 32-bit int (4 bytes) +}; + +struct sockaddr_storage { + sa_family_t ss_family; // address family + + // all this is padding, implementation specific, ignore it: + char __ss_pad1[_SS_PAD1SIZE]; + int64_t __ss_align; + char __ss_pad2[_SS_PAD2SIZE]; +}; + +int getaddrinfo(const char *node, // e.g. "www.example.com" or IP + const char *service, // e.g. "http" or port number + const struct addrinfo *hints, + struct addrinfo **res); + + +// sockets! +#include <sys/types.h> +#include <sys/socket.h> + +int socket(int domain, int type, int protocol); + +int s; +struct addrinfo hints, *res; + +// do the lookup +// [pretend we already filled out the "hints" struct] +getaddrinfo("www.example.com", "http", &hints, &res); + +// again, you should do error-checking on getaddrinfo(), and walk +// the "res" linked list looking for valid entries instead of just +// assuming the first one is good (like many of these examples do). +// See the section on client/server for real examples. + +s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
\ No newline at end of file Binary files differdiff --git a/server.c b/server.c new file mode 100644 index 0000000..ea7d62c --- /dev/null +++ b/server.c @@ -0,0 +1,144 @@ +/* +** server.c -- a stream socket server demo +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <sys/wait.h> +#include <signal.h> + +#define PORT "3490" // the port users will be connecting to + +#define BACKLOG 10 // how many pending connections queue will hold + +#define MAXDATASIZE 100 // max number of bytes we can get at once + + +void sigchld_handler(int s) +{ + // waitpid() might overwrite errno, so we save and restore it: + int saved_errno = errno; + + while(waitpid(-1, NULL, WNOHANG) > 0); + + errno = saved_errno; +} + + +// get sockaddr, IPv4 or IPv6: +void *get_in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + +int main(void) +{ + int sockfd, new_fd, numbytes; // listen on sock_fd, new connection on new_fd + char buf[MAXDATASIZE]; + struct addrinfo hints, *servinfo, *p; + struct sockaddr_storage their_addr; // connector's address information + socklen_t sin_size; + struct sigaction sa; + int yes=1; + char s[INET6_ADDRSTRLEN]; + int rv; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; // only IPv4 + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; // use my IP + + if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return 1; + } + + // loop through all the results and bind to the first we can + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + perror("server: socket"); + continue; + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, + sizeof(int)) == -1) { + perror("setsockopt"); + exit(1); + } + + if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd); + perror("server: bind"); + continue; + } + + break; + } + + freeaddrinfo(servinfo); // all done with this structure + + if (p == NULL) { + fprintf(stderr, "server: failed to bind\n"); + exit(1); + } + + if (listen(sockfd, BACKLOG) == -1) { + perror("listen"); + exit(1); + } + + sa.sa_handler = sigchld_handler; // reap all dead processes + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if (sigaction(SIGCHLD, &sa, NULL) == -1) { + perror("sigaction"); + exit(1); + } + + printf("server: waiting for connections...\n"); + + while(1) { // main accept() loop + sin_size = sizeof their_addr; + new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); + if (new_fd == -1) { + perror("accept"); + continue; + } + + inet_ntop(their_addr.ss_family, + get_in_addr((struct sockaddr *)&their_addr), + s, sizeof s); + printf("server: got connection from %s\n", s); + + if (!fork()) { // this is the child process + + close(sockfd); // child doesn't need the listener + if (send(new_fd, "Hello, world!", 13, 0) == -1) + perror("send"); + // close(new_fd); + if ((numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0)) == -1) { + perror("recv"); + exit(1); + } + buf[numbytes] = '\0'; + printf("server: received '%s'\n",buf); + exit(0); + } + close(new_fd); // parent doesn't need this + } + + return 0; +}
\ No newline at end of file diff --git a/server.dSYM/Contents/Info.plist b/server.dSYM/Contents/Info.plist new file mode 100644 index 0000000..d2b6274 --- /dev/null +++ b/server.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> + <dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleIdentifier</key> + <string>com.apple.xcode.dsym.server</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundlePackageType</key> + <string>dSYM</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>1</string> + </dict> +</plist> diff --git a/server.dSYM/Contents/Resources/DWARF/server b/server.dSYM/Contents/Resources/DWARF/server Binary files differnew file mode 100644 index 0000000..22ad6d7 --- /dev/null +++ b/server.dSYM/Contents/Resources/DWARF/server diff --git a/talker.c b/talker.c new file mode 100644 index 0000000..bb801e5 --- /dev/null +++ b/talker.c @@ -0,0 +1,67 @@ +/* +** talker.c -- a datagram "client" demo +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#define SERVERPORT "4950" // the port users will be connecting to + +int main(int argc, char *argv[]) +{ + int sockfd; + struct addrinfo hints, *servinfo, *p; + int rv; + int numbytes; + + if (argc != 3) { + fprintf(stderr,"usage: talker hostname message\n"); + exit(1); + } + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET6; // set to AF_INET to use IPv4 + hints.ai_socktype = SOCK_DGRAM; + + if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return 1; + } + + // loop through all the results and make a socket + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + perror("talker: socket"); + continue; + } + + break; + } + + if (p == NULL) { + fprintf(stderr, "talker: failed to create socket\n"); + return 2; + } + + if ((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, + p->ai_addr, p->ai_addrlen)) == -1) { + perror("talker: sendto"); + exit(1); + } + + freeaddrinfo(servinfo); + + printf("talker: sent %d bytes to %s\n", numbytes, argv[1]); + close(sockfd); + + return 0; +}
\ No newline at end of file |