Yesterday I posted a request for a code review. After reviewing the code and the reviews, and after some sleep, I decided I can do better. In fact I logged on with the intent of deleting the question just as the first review was posted; so I was stuck with it.This is pretty much the same program, but it is the result of much more effort. It even includes a thing I've never used before: select. To use the program, and the previous program, the user provides two arguments: the target IP and the target port. Contrary to the last program, this program terminates with ctrlc.#include <signal.h>#include <arpa/inet.h>#include <assert.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <unistd.h>#define BUFLEN  1024#define STDIN   0#define STDOUT  1void sigint_handle(int dummy);int connect_to(char *host, int port);int transfer(int fd_in, char *buf, int buf_len, int fd_out);//  boolean flag for program continuationvolatile int run = 1;//  entry point of linux ELFint main(int args, char **argv) {    int sd, ret_val = 0;    fd_set fds;    struct timeval tv;    char buffer[BUFLEN];    assert(args == 3);    signal(SIGINT, sigint_handle);    sd = connect_to(argv[1], atoi(argv[2]));    FD_ZERO(&fds);    tv.tv_sec = 0;    tv.tv_usec = 10000;    while (run) {        FD_SET(STDIN, &fds);        FD_SET(sd, &fds);        ret_val = select(sd + 1, &fds, NULL, NULL, &tv);        if (FD_ISSET(STDIN, &fds))            ret_val = transfer(STDIN, buffer, BUFLEN, sd);        else if (FD_ISSET(sd, &fds))            ret_val = transfer(sd, buffer, BUFLEN, STDOUT);        assert(ret_val == 0);    }    close(sd);    return 0;}//  SIGINT handlervoid sigint_handle(int dummy) {    run = 0;}//  a very picky connect to tcp host functionint connect_to(char *host, int port) {    struct sockaddr_in addr;    int sd = socket(AF_INET, SOCK_STREAM, 0);    memset(&addr, 0, sizeof(addr));    assert(sd > -1);    addr.sin_family = AF_INET;    assert(inet_pton(AF_INET, host, &addr.sin_addr) > 0);    addr.sin_port = htons(port);    assert(connect(sd, (struct sockaddr *)&addr, sizeof(addr)) > -1);    return sd;}//  transfer function - basically a one time pipeint transfer(int fd_in, char *buf, int buf_len, int fd_out) {    int len = read(fd_in, buf, buf_len);    return len - write(fd_out, buf, len);}I should note it's not really meant to be user friendly. It's meant to do one specific task as a subprocess, and panics otherwise; again using ctrlc to quit.import subprocessimport signalimport osimport socketdef dostuff():        host = socket.gethostbyname(google.com)        proc = subprocess.Popen([./client  + host +  80],                        stdout=subprocess.PIPE, shell=True,                        stdin=subprocess.PIPE)        global pid        pid = proc.pid        proc.stdin.write(GET /\n\n)        while proc.poll() is None:                print proc.stdout.readline()if __name__ == __main__:        try: dostuff()        except: os.kill(pid, signal.SIGINT)
Raw Text TCP Client
c;socket;tcp;client
Detect closed connection 1select promises that a read wouldn't block. This is a case when there are data, but this is also a case that the remote end is closed. In this case read immediately returns 0. Without testing for len > 0 in transfer end up in an infinite empty select/read cycle.Detect closed connection 2The remote may close connection while you are attempting to write. This would result in SIGPIPE most likely killing the program. You need a handler, as simple as setting a flag to be tested in the main loop.assert is for detecting bugs. Is not a way to handle errors.