Impromptu TCP sender/receiver Every once in a while I need to get some random computer thing done; so I write something to do it for me. This is one of those. It needed to be able to send text to, and receive text from, a server - without blocking. I am asking for feedback with the premise of what kind of code this is: A one-use hack.

#include &lt;stdio.h&gt;
#include &lt;assert.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;string.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;arpa/inet.h&gt;
#include &lt;ctype.h&gt;

#define BUFLEN 1024

volatile static int run = 1;

void sendx(int sd) {
    int sent, i;
    char buffer[BUFLEN], ch;
    do {
        i = 0;
        do {
            ch = getc(stdin);
            buffer[i] = ch;
            i++;
        } while (ch != '\n' &amp;&amp; i &lt; BUFLEN);
        sent = write(sd, buffer, i);
    } while (sent == i &amp;&amp; run);
}

void recvx(int sd) {
    char nothing[] = { '?' };
    int len, i;
    char buffer[BUFLEN];
    do {
        len = read(sd, buffer, BUFLEN);
        i = 0;
        while (i &lt; len) {
            if (isprint(buffer[i]))
                write(1, buffer + i, 1);
            else write(1, nothing, 1);
            i++;
        }
    } while (len &gt; 0 &amp;&amp; run);
    close(sd);
    nothing[0] = '\n';
    write(0, nothing, 1);
    fflush(stdin);
}

int main(int argc, char **argv) {
    int sd, pid;
    struct sockaddr_in addr;

    memset(&amp;addr, 0, sizeof(struct sockaddr));

    assert(argc == 3);
    sd = socket(AF_INET, SOCK_STREAM, 0);
    addr.sin_family = AF_INET;
    assert(inet_pton(AF_INET, argv[1], &amp;addr.sin_addr) &gt; 0);
    addr.sin_port = htons(atoi(argv[2]));
    assert(sd &gt; -1);
    assert(connect(sd, (struct sockaddr *)&amp;addr, sizeof(addr)) &gt; -1);
    pid = fork();
    assert(pid &gt; -1);
    if (pid == 0)   sendx(sd);
    else        recvx(sd);
    run = 0;
    return 0;
}
Some of the logic is nicely encapsulated in functions sendx and recvx, but then main disappoints with its lump of code. It would be better to leave main in charge of parsing and validating the command line arguments, and extract the rest to functions with descriptive names. 

In main the assert(argc == 3) should come before the first memset: no need to initialize memory if you might not use it.

In sendx, the variable i is used for two purposes: loop variable for reading input, and input size. If you extract the input reading to a function that returns the number of characters read, then in sendx you can store that in a variable with a descriptive name, and the logic of the main responsibility of this method will become clearer.