Parent directory tcp-echo-client.c tcp-echo-server.c tcp-recver.c tcp-sender.c toupper.c
Download
/* * tcp-echo-client.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <unistd.h> #include <sys/wait.h> #include <sys/stat.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> static void die(const char *s) { perror(s); exit(1); } int main(int argc, char **argv) { if (argc != 3) { fprintf(stderr, "usage: %s <server-ip> <server-port>\n", argv[0]); exit(1); } const char *ip = argv[1]; unsigned short port = atoi(argv[2]); // Create a socket for TCP connection int sock; // socket descriptor if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) die("socket failed"); // Construct a server address structure struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); // must zero out the structure servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = inet_addr(ip); servaddr.sin_port = htons(port); // must be in network byte order // Establish a TCP connection to the server if (connect(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) die("connect failed"); // Read a line from stdin and send it to the server char buf[100]; if (fgets(buf, sizeof(buf), stdin) == NULL) { die("fgets returned NULL"); } size_t len = strlen(buf); /* * send(int socket, const void *buffer, size_t length, int flags) * * - normally, send() blocks until it sends all bytes requested * - returns num bytes sent or -1 for error * - send(sock,buf,len,0) is equivalent to write(sock,buf,len) */ if (send(sock, buf, len, 0) != len) die("send failed"); // Receive the responses from the server and print them /* * recv(int socket, void *buffer, size_t length, int flags) * * - normally, recv() blocks until it has received at least 1 byte * - returns num bytes received, 0 if connection closed, -1 if error * - recv(sock,buf,len,0) is equivalent to read(sock,buf,len) */ int r; while (len > 0 && (r = recv(sock, buf, sizeof(buf), 0)) > 0) { printf("RECEIVED: ["); fwrite(buf, 1, r, stdout); printf("]\n"); len -= r; } if (r < 0) die("recv failed"); // Clean-up close(sock); return 0; }
/* * tcp-echo-server.c */ #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <unistd.h> #include <sys/wait.h> #include <sys/stat.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> static void die(const char *s) { perror(s); exit(1); } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: %s <server-port>\n", argv[0]); exit(1); } unsigned short port = atoi(argv[1]); // Create a listening socket (also called server socket) int servsock; if ((servsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) die("socket failed"); // Construct local address structure struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // any network interface servaddr.sin_port = htons(port); // Bind to the local address if (bind(servsock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) die("bind failed"); // Start listening for incoming connections if (listen(servsock, 5 /* queue size for connection requests */ ) < 0) die("listen failed"); int r; char buf[10]; int clntsock; socklen_t clntlen; struct sockaddr_in clntaddr; while (1) { // Accept an incoming connection fprintf(stderr, "waiting for client ... "); clntlen = sizeof(clntaddr); // initialize the in-out parameter if ((clntsock = accept(servsock, (struct sockaddr *) &clntaddr, &clntlen)) < 0) die("accept failed"); // accept() returned a connected socket (also called client socket) // and filled in the client's address into clntaddr fprintf(stderr, "client ip: %s\n", inet_ntoa(clntaddr.sin_addr)); // Receive msg from client, capitalize the 1st char, send it back while ((r = recv(clntsock, buf, sizeof(buf), 0)) > 0) { *buf = toupper(*buf); if (send(clntsock, buf, r, 0) != r) { fprintf(stderr, "ERR: send failed\n"); break; } } if (r < 0) { fprintf(stderr, "ERR: recv failed\n"); } // Client closed the connection (r==0) or there was an error // Either way, close the client socket and go back to accept() close(clntsock); } }
/* * tcp-recver.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <unistd.h> #include <sys/wait.h> #include <sys/stat.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> static void die(const char *s) { perror(s); exit(1); } int main(int argc, char **argv) { if (argc != 3) { fprintf(stderr, "usage: %s <server-port> <filebase>\n", argv[0]); exit(1); } unsigned short port = atoi(argv[1]); const char *filebase = argv[2]; // Create a listening socket (also called server socket) int servsock; if ((servsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) die("socket failed"); // Construct local address structure struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // any network interface servaddr.sin_port = htons(port); // Bind to the local address if (bind(servsock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) die("bind failed"); // Start listening for incoming connections if (listen(servsock, 5 /* queue size for connection requests */ ) < 0) die("listen failed"); int clntsock; socklen_t clntlen; struct sockaddr_in clntaddr; FILE *fp; unsigned int filesuffix = 0; // Variable-length array (VLA) is used here to show that it's legal in C. // But VLA should be avoided in most cases. The VLA declaration below // could and should be replaced with heap allocation: // // char *filename = malloc(strlen(filebase) + 100); // char filename[strlen(filebase) + 100]; int r; char buf[4096]; uint32_t size, size_net, remaining, limit; struct stat st; while (1) { // Accept an incoming connection clntlen = sizeof(clntaddr); // initialize the in-out parameter if ((clntsock = accept(servsock, (struct sockaddr *) &clntaddr, &clntlen)) < 0) die("accept failed"); // accept() returned a connected socket (also called client socket) // and filled in the client's address into clntaddr fprintf(stderr, "client ip: %s\n", inet_ntoa(clntaddr.sin_addr)); sprintf(filename, "%s.%u", filebase, filesuffix++); fprintf(stderr, "file name: %s\n", filename); if ((fp = fopen(filename, "wb")) == NULL) die(filename); // First, receive file size r = recv(clntsock, &size_net, sizeof(size_net), MSG_WAITALL); if (r != sizeof(size_net)) { if (r < 0) die("recv failed"); else if (r == 0) die("connection closed prematurely"); else die("didn't receive uint32"); } size = ntohl(size_net); // convert it to host byte order fprintf(stderr, "file size received: %u\n", size); // Second, receive the file content remaining = size; while (remaining > 0) { limit = remaining > sizeof(buf) ? sizeof(buf) : remaining; r = recv(clntsock, buf, limit, 0); if (r < 0) die("recv failed"); else if (r == 0) die("connection closed prematurely"); else { remaining -= r; if (fwrite(buf, 1, r, fp) != r) die("fwrite failed"); } } assert(remaining == 0); fclose(fp); // Third, send the file size back as acknowledgement stat(filename, &st); size = st.st_size; fprintf(stderr, "file size on disk: %u\n\n", size); size_net = htonl(size); if (send(clntsock, &size_net, sizeof(size_net), 0) != sizeof(size_net)) die("send size failed"); // Finally, close the client connection and go back to accept() close(clntsock); } }
/* * tcp-sender.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <unistd.h> #include <sys/wait.h> #include <sys/stat.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> static void die(const char *s) { perror(s); exit(1); } int main(int argc, char **argv) { if (argc != 4) { fprintf(stderr, "usage: %s <server-ip> <server-port> <filename>\n", argv[0]); exit(1); } const char *ip = argv[1]; unsigned short port = atoi(argv[2]); const char *filename = argv[3]; // Open the file to send FILE *fp = fopen(filename, "rb"); if (fp == NULL) die(filename); // Create a socket for TCP connection int sock; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) die("socket failed"); // Construct a server address structure struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); // must zero out the structure servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = inet_addr(ip); servaddr.sin_port = htons(port); // must be in network byte order // Establish a TCP connection to the server if (connect(sock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) die("connect failed"); // First, send file size as 4-byte unsigned int in network byte order struct stat st; stat(filename, &st); uint32_t size = st.st_size; fprintf(stderr, "file size: %u\n", size); uint32_t size_net = htonl(size); /* * send(int socket, const void *buffer, size_t length, int flags) * * - normally, send() blocks until it sends all bytes requested * - returns num bytes sent or -1 for error * - send(sock,buf,len,0) is equivalent to write(sock,buf,len) */ if (send(sock, &size_net, sizeof(size_net), 0) != sizeof(size_net)) die("send size failed"); // Second, send the file content char buf[4096]; unsigned int n; unsigned int total = 0; while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { if (send(sock, buf, n, 0) != n) die("send content failed"); else total += n; } if (ferror(fp)) { // fread() returns 0 on EOF or error, so we check if error occurred die("fread failed"); } fclose(fp); fprintf(stderr, "bytes sent: %u\n", total); // Third, receive file size back from the server as acknowledgement uint32_t ack, ack_net; /* * recv(int socket, void *buffer, size_t length, int flags) * * - normally, recv() blocks until it has received at least 1 byte * - returns num bytes received, 0 if connection closed, -1 if error * - recv(sock,buf,len,0) is equivalent to read(sock,buf,len) * * - With TCP sockets, we can receive less data than we requested; * MSG_WAITALL flag changes this behavior -- it requests that the * operation block until the full request is satisfied. */ int r = recv(sock, &ack_net, sizeof(ack_net), MSG_WAITALL); if (r != sizeof(ack_net)) { if (r < 0) die("recv failed"); else if (r == 0) die("connection closed prematurely"); else die("didn't receive uint32"); } ack = ntohl(ack_net); // convert it back to host byte order if (ack != size) die("ack!=size"); // recv() will return 0 when the server closes the TCP connection char x; r = recv(sock, &x, 1, 0); assert(r == 0); // Clean-up close(sock); return 0; }
#include <ctype.h> #include <stdio.h> #include <unistd.h> int main() { char c; #ifdef STDIO FILE *fp_in = stdin; FILE *fp_out = stdout; while (fread(&c, 1, 1, fp_in) == 1) { c = toupper(c); fwrite(&c, 1, 1, fp_out); } #endif #ifdef UNIX int fd_in = 0; int fd_out = 1; while (read(fd_in, &c, 1) == 1) { c = toupper(c); write(fd_out, &c, 1); } #endif }