Tag Archives: Network Programming

Downloading a Web page in Java using a java.net.Socket

import java.io.*;
import java.net.*;
 
public class SocketHTTPClient {
    public static void main(String[] args) {
         
        String hostName = "www.martinbroadhurst.com";
        int portNumber = 80;
 
        try {
            Socket socket = new Socket(hostName, portNumber);
            PrintWriter out =
                new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in =
                new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));
            out.println("GET / HTTP/1.1\nHost: www.martinbroadhurst.com\n\n");
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                System.out.println(inputLine);
            }
        } catch (UnknownHostException e) {
            System.err.println("Don't know about host " + hostName);
            System.exit(1);
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection to " +
                hostName);
            System.exit(1);
        } 
    }
}

Downloading a Web page in C using a Windows socket

/* Link with Ws2_32.lib */
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <stdio.h>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>


int main(void)
{
	WSADATA wsaData;
	WORD wVersion;
	SOCKET sock;
	char host[] = "www.martinbroadhurst.com";
	char port[] = "80";
	struct addrinfo hints, *res;
	char message[] = "GET / HTTP/1.1\nHost: www.martinbroadhurst.com\n\n";
	char buf[1024];
	int bytes_read;
	int status;

	wVersion = MAKEWORD(1, 1);
	if (WSAStartup(wVersion, &wsaData) != 0) {
		printf("Couldn't initialise WinSock\n");
		return 1;
	}

	ZeroMemory(&hints, sizeof hints);
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	status = getaddrinfo(host, port, &hints, &res);
	if (status != 0) {
		perror("getaddrinfo");
        WSACleanup();
		return 1;
	}
	sock = socket(AF_INET, SOCK_STREAM, 0);

	status = connect(sock, res->ai_addr, res->ai_addrlen);
	if (status == SOCKET_ERROR) {
		perror("connect");
        WSACleanup();
		return 1;
	}

	send(sock, message, sizeof(message), 0);

    do {
		bytes_read = recv(sock, buf, sizeof(buf), 0);
		if (bytes_read == SOCKET_ERROR) {
			perror("recv");
		}
		else {
			printf("%.*s", bytes_read, buf);
		}
	} while (bytes_read > 0);

	closesocket(sock);
	WSACleanup();
    return 0;
}

Reference: Using Winsock

Downloading a Web page in C using a socket

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* close() */
#include <sys/socket.h>
#include <netdb.h>

int main(void)
{
    int sock;
	char host[] = "www.martinbroadhurst.com";
	char port[] = "80";
	struct addrinfo hints, *res;
	char message[] = "GET / HTTP/1.1\nHost: www.martinbroadhurst.com\n\n";
	unsigned int i;
    char buf[1024];
    int bytes_read;
	int status;

	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	status = getaddrinfo(host, port, &hints, &res);
	if (status != 0) {
		perror("getaddrinfo");
		return 1;
	}
	sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (sock == -1) {
		perror("socket");
		return 1;
	}
	status = connect(sock, res->ai_addr, res->ai_addrlen);
    if (status == -1) {
		perror("connect");
		return 1;
    }
	freeaddrinfo(res);
    send(sock, message, strlen(message), 0);

    do {
		bytes_read = recv(sock, buf, 1024, 0);
		if (bytes_read == -1) {
			perror("recv");
		}
        else {
		    printf("%.*s", bytes_read, buf);
        }
    } while (bytes_read > 0);

    close(sock);

    return 0;
}

TCP Proxy

This is about as simple as a TCP proxy can be. It accepts one client connection at a time, but you can easily allow it to accept more by using the methods demonstrated in the server examples. You can use it as a starting point to write a more sophisticated proxy, that, for example, writes the transfers to a file, or modifies the data being exchanged.

The thing to remember when writing a proxy is that you need to call select before every call to read or recv, unless you know how many more bytes there are. This is because if there are no more bytes left, read and recv will block, which will cause the proxy to freeze. read and recv only return 0 when the peer has disconnected.

 /* 
 *  A simple TCP proxy
 *  by Martin Broadhurst (www.martinbroadhurst.com)
 *  Usage: tcpproxy local_host local_port remote_host remote_port
 */

#include <stdio.h>
#include <string.h> /* memset() */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <signal.h>

#define BACKLOG  10      /* Passed to listen() */
#define BUF_SIZE 4096    /* Buffer for  transfers */

unsigned int transfer(int from, int to)
{
    char buf[BUF_SIZE];
    unsigned int disconnected = 0;
    size_t bytes_read, bytes_written;
    bytes_read = read(from, buf, BUF_SIZE);
    if (bytes_read == 0) {
        disconnected = 1;
    }
    else {
        bytes_written = write(to, buf, bytes_read);
        if (bytes_written == -1) {
            disconnected = 1;
        }
    }
    return disconnected;
}

void handle(int client, const char *remote_host, const char *remote_port)
{
    struct addrinfo hints, *res;
    int server = -1;
    unsigned int disconnected = 0;
    fd_set set;
    unsigned int max_sock;

    /* Get the address info */
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    if (getaddrinfo(remote_host, remote_port, &hints, &res) != 0) {
        perror("getaddrinfo");
        close(client);
        return;
    }

    /* Create the socket */
    server = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (server == -1) {
        perror("socket");
        close(client);
        return;
    }

    /* Connect to the host */
    if (connect(server, res->ai_addr, res->ai_addrlen) == -1) {
        perror("connect");
        close(client);
        return;
    }

    if (client > server) {
        max_sock = client;
    }
    else {
        max_sock = server;
    }

    /* Main transfer loop */
    while (!disconnected) {
        FD_ZERO(&set);
        FD_SET(client, &set);
        FD_SET(server, &set);
        if (select(max_sock + 1, &set, NULL, NULL, NULL) == -1) {
            perror("select");
            break;
        }
        if (FD_ISSET(client, &set)) {
            disconnected = transfer(client, server);
        }
        if (FD_ISSET(server, &set)) {
            disconnected = transfer(server, client);
        }
    }
    close(server);
    close(client);
}

int main(int argc, char **argv)
{
    int sock;
    struct addrinfo hints, *res;
    int reuseaddr = 1; /* True */
    const char *local_host, *local_port, *remote_host, *remote_port;

    /* Get the local and remote hosts and ports from the command line */
    if (argc < 5) {
        fprintf(stderr, "Usage: tcpproxy local_host local_port remote_host remote_port\n");
        return 1;
    }
    local_host = argv[1];
    local_port = argv[2];
    remote_host = argv[3];
    remote_port = argv[4];

    /* Get the address info */
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    if (getaddrinfo(local_host, local_port, &hints, &res) != 0) {
        perror("getaddrinfo");
        return 1;
    }

    /* Create the socket */
    sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sock == -1) {
        perror("socket");
        freeaddrinfo(res);
        return 1;
    }

    /* Enable the socket to reuse the address */
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1) {
        perror("setsockopt");
        freeaddrinfo(res);
        return 1;
    }

    /* Bind to the address */
    if (bind(sock, res->ai_addr, res->ai_addrlen) == -1) {
        perror("bind");
        freeaddrinfo(res);
        return 1;
    }

    /* Listen */
    if (listen(sock, BACKLOG) == -1) {
        perror("listen");
        freeaddrinfo(res);
        return 1;
    }

    freeaddrinfo(res);

    /* Ignore broken pipe signal */
    signal(SIGPIPE, SIG_IGN);
 
    /* Main loop */
    while (1) {
        socklen_t size = sizeof(struct sockaddr_in);
        struct sockaddr_in their_addr;
        int newsock = accept(sock, (struct sockaddr*)&their_addr, &size);

        if (newsock == -1) {
            perror("accept");
        }
        else {
            printf("Got a connection from %s on port %d\n",
                    inet_ntoa(their_addr.sin_addr), htons(their_addr.sin_port));
            handle(newsock, remote_host, remote_port);
        }
    }

    close(sock);

    return 0;
}

TCP Proxy for Windows

This is the Windows version of TCP Proxy.

/* 
 *  A simple TCP proxy for Windows
 *  by Martin Broadhurst (www.martinbroadhurst.com)
 *  Link with Ws2_32.lib
 *  Usage: tcpproxy local_host local_port remote_host remote_port
 */

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#define _WINSOCK_DEPRECATED_NO_WARNINGS /* inet_ntoa */

#include <stdio.h>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#define BACKLOG  10      /* Passed to listen() */
#define BUF_SIZE 4096    /* Buffer for  transfers */

unsigned int transfer(SOCKET from, SOCKET to)
{
	char buf[BUF_SIZE];
	unsigned int disconnected = 0;
	size_t bytes_read, bytes_written;
	bytes_read = recv(from, buf, BUF_SIZE, 0);
	if (bytes_read == 0) {
		disconnected = 1;
	}
	else {
		bytes_written = send(to, buf, bytes_read, 0);
		if (bytes_written == -1) {
			disconnected = 1;
		}
	}
	return disconnected;
}

void handle(SOCKET client, const char *remote_host, const char *remote_port)
{
	struct addrinfo hints, *res;
	SOCKET server = -1;
	unsigned int disconnected = 0;
	fd_set set;
	unsigned int max_sock;

	/* Get the address info */
	ZeroMemory(&hints, sizeof hints);
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	if (getaddrinfo(remote_host, remote_port, &hints, &res) != 0) {
		perror("getaddrinfo");
		closesocket(client);
		return;
	}

	/* Create the socket */
    server = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (server == INVALID_SOCKET) {
		perror("socket");
		closesocket(client);
		return;
	}

	/* Connect to the host */
	if (connect(server, res->ai_addr, res->ai_addrlen) == -1) {
		perror("connect");
		closesocket(client);
		return;
    }

	if (client > server) {
		max_sock = client;
	}
	else {
		max_sock = server;
	}

	/* Main transfer loop */
	while (!disconnected) {
		FD_ZERO(&set);
		FD_SET(client, &set);
		FD_SET(server, &set);
		if (select(max_sock + 1, &set, NULL, NULL, NULL) == SOCKET_ERROR) {
			perror("select");
			break;
		}
		if (FD_ISSET(client, &set)) {
			disconnected = transfer(client, server);
		}
		if (FD_ISSET(server, &set)) {
			disconnected = transfer(server, client);
		}
	}
	if (server != -1) {
		closesocket(server);
	}
	closesocket(client);
}

int main(int argc, char **argv)
{
	WORD wVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	int iResult;
    SOCKET sock;
	struct addrinfo hints, *res;
	int reuseaddr = 1; /* True */
	const char *local_host, *local_port, *remote_host, *remote_port;

	/* Initialise Winsock */
	if (iResult = (WSAStartup(wVersion, &wsaData)) != 0) {
		fprintf(stderr, "WSAStartup failed: %d\n", iResult);
		return 1;
	}

	/* Get the local and remote hosts and ports from the command line */
	if (argc < 5) {
		fprintf(stderr, "Usage: tcpproxy local_host local_port remote_host remote_port\n");
		return 1;
	}
	local_host = argv[1];
	local_port = argv[2];
	remote_host = argv[3];
	remote_port = argv[4];

	/* Get the address info */
	ZeroMemory(&hints, sizeof hints);
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	if (getaddrinfo(local_host, local_port, &hints, &res) != 0) {
		perror("getaddrinfo");
		WSACleanup();
		return 1;
	}

	/* Create the socket */
    sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (sock == INVALID_SOCKET) {
		perror("socket");
		WSACleanup();
		return 1;
	}

	/* Enable the socket to reuse the address */
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr, 
		sizeof(int)) == SOCKET_ERROR) {
		perror("setsockopt");
		WSACleanup();
		return 1;
	}

	/* Bind to the address */
    if (bind(sock, res->ai_addr, res->ai_addrlen) == SOCKET_ERROR) {
        perror("bind");
		WSACleanup();
        return 1;
    }

	/* Listen */
    if (listen(sock, BACKLOG) == SOCKET_ERROR) {
        perror("listen");
		WSACleanup();
        return 1;
    }

	freeaddrinfo(res);
 
	/* Main loop */
	while (1) {
		size_t size = sizeof(struct sockaddr_in);
		struct sockaddr_in their_addr;
		int newsock = accept(sock, (struct sockaddr*)&their_addr, &size);

		if (newsock == INVALID_SOCKET) {
			perror("accept");
		}
		else {
			printf("Got a connection from %s on port %d\n", 
					inet_ntoa(their_addr.sin_addr), htons(their_addr.sin_port));
			handle(newsock, remote_host, remote_port);
		}
	}

    closesocket(sock);
	WSACleanup();

    return 0;
}

Select server for windows

This is the Windows version of the Select Server.

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <stdio.h>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#define PORT    "32001" /* Port to listen on */
#define BACKLOG 10		/* Passed to listen() */

void handle(SOCKET newsock, fd_set *set)
{
    /* send(), recv(), closesocket() */
	/* Call FD_CLR(newsock, set) on disconnection */
}

int main(void)
{
    WORD wVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	int iResult;
	SOCKET sock;
	fd_set socks;
	fd_set readsocks;
	SOCKET maxsock;
	int reuseaddr = 1; /* True */
	struct addrinfo hints, *res;

	/* Initialise Winsock */
	if (iResult = (WSAStartup(wVersion, &wsaData)) != 0) {
		printf("WSAStartup failed: %d\n", iResult);
		return 1;
	}

	/* Get the address info */
	ZeroMemory(&hints, sizeof hints);
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	if (getaddrinfo(NULL, PORT, &hints, &res) != 0) {
		perror("getaddrinfo");
		WSACleanup();
		return 1;
	}

	/* Create the socket */
    sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (sock == -1) {
		perror("socket");
		WSACleanup();
		return 1;
	}

	/* Enable the socket to reuse the address */
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr, 
				sizeof(int)) == SOCKET_ERROR) {
		perror("setsockopt");
		WSACleanup();
		return 1;
	}

	/* Bind to the address */
    if (bind(sock, res->ai_addr, res->ai_addrlen) == SOCKET_ERROR) {
        perror("bind");
		WSACleanup();
        return 1;
    }

	/* Listen */
    if (listen(sock, BACKLOG) == SOCKET_ERROR) {
        perror("listen");
		WSACleanup();
        return 1;
    }

	/* Set up the fd_set */
	FD_ZERO(&socks);
	FD_SET(sock, &socks);
	maxsock = sock;

	/* Main loop */
	while (1) {
		SOCKET s;
		readsocks = socks;
		if (select(maxsock + 1, &readsocks, NULL, NULL, NULL) == SOCKET_ERROR) {
			perror("select");
			WSACleanup();
			return 1;
		}
		for (s = 0; s <= maxsock; s++) {
			if (FD_ISSET(s, &readsocks)) {
				printf("Socket %d was ready\n", s);
				if (s == sock) {
					/* New connection */
					SOCKET newsock;
					struct sockaddr_in their_addr;
					size_t size = sizeof(struct sockaddr_in);

					newsock = accept(sock, (struct sockaddr*)&their_addr, &size);
					if (newsock == INVALID_SOCKET) {
						perror("accept");
					}
					else {
						printf("Got a connection from %s on port %d\n", 
								inet_ntoa(their_addr.sin_addr), htons(their_addr.sin_port));
						FD_SET(newsock, &socks);
						if (newsock > maxsock) {
							maxsock = newsock;
						}
					}
				}
				else {
					/* Handle read or disconnection */
					handle(s, &socks);
				}
			}
		}
	}

	/* Clean up */
    closesocket(sock);
	WSACleanup();

    return 0;
}

Select server

This server uses the select function to determine when sockets are ready for reading, and when clients have disconnected. It is not as fast as forking or using threads, and cannot exploit multi-cores, but is less resource intensive, and so will scale up to far more connections.

In order to prevent the handling of individual clients from starving others, it may necessary to limit how much data is read per client in response to each select call. Additionally, this example assumes that calls to recv will not block. If they can block, it may be necessary to put the socket in non-blocking mode using fcntl with the F_SETFL command and the O_NONBLOCK flag.

#include <stdio.h>
#include <string.h> /* memset() */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>

#define PORT    "32001" /* Port to listen on */
#define BACKLOG     10  /* Passed to listen() */

void handle(int newsock, fd_set *set)
{
    /* send(), recv(), close() */
	/* Call FD_CLR(newsock, set) on disconnection */
}

int main(void)
{
    int sock;
	fd_set socks;
	fd_set readsocks;
	int maxsock;
	int reuseaddr = 1; /* True */
	struct addrinfo hints, *res;

	/* Get the address info */
	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	if (getaddrinfo(NULL, PORT, &hints, &res) != 0) {
		perror("getaddrinfo");
		return 1;
	}

	/* Create the socket */
    sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (sock == -1) {
		perror("socket");
		return 1;
	}

	/* Enable the socket to reuse the address */
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1) {
		perror("setsockopt");
		return 1;
	}

	/* Bind to the address */
    if (bind(sock, res->ai_addr, res->ai_addrlen) == -1) {
        perror("bind");
        return 1;
    }

	freeaddrinfo(res);

	/* Listen */
    if (listen(sock, BACKLOG) == -1) {
        perror("listen");
        return 1;
    }

	/* Set up the fd_set */
	FD_ZERO(&socks);
	FD_SET(sock, &socks);
	maxsock = sock;

	/* Main loop */
	while (1) {
		unsigned int s;
		readsocks = socks;
		if (select(maxsock + 1, &readsocks, NULL, NULL, NULL) == -1) {
			perror("select");
			return 1;
		}
		for (s = 0; s <= maxsock; s++) {
			if (FD_ISSET(s, &readsocks)) {
				printf("socket %d was ready\n", s);
				if (s == sock) {
					/* New connection */
					int newsock;
					struct sockaddr_in their_addr;
					socklen_t size = sizeof(struct sockaddr_in);
					newsock = accept(sock, (struct sockaddr*)&their_addr, &size);
					if (newsock == -1) {
						perror("accept");
					}
					else {
						printf("Got a connection from %s on port %d\n", 
								inet_ntoa(their_addr.sin_addr), htons(their_addr.sin_port));
						FD_SET(newsock, &socks);
						if (newsock > maxsock) {
							maxsock = newsock;
						}
					}
				}
				else {
					/* Handle read or disconnection */
					handle(s, &socks);
				}
			}
		}

	}

    close(sock);

    return 0;
}