 Parent directory
Parent directory
 tcp-echo-client.c
tcp-echo-client.c
 tcp-echo-server.c
tcp-echo-server.c
 tcp-recver.c
tcp-recver.c
 tcp-sender.c
tcp-sender.c
 toupper.c
toupper.c
/*
 * 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
}