Search code examples
pythonclinuxnetwork-programmingtcpclient

Connection refused when running TCP client


I'm working on a lab project that requires me to write a TCP client in C and a TCP server in Python.

The issue I'm having right now with the TCP client is that every time I try to connect the client to the server which is also running on my PC, there is a "Connection refused" error and the errno is 111. (The TCP server works just fine since every time I type in localhost:5566 on web browser, the server received some information)

By the way, I'm running all the code on a virtual machine with Ubuntu 18.04.6 installed.

The C code for the client and the Python code for the server is attached.

TCP client code (in C)

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <errno.h>

#define SERVER_IP   "127.0.0.1"   /* Dotted-decimal representation of server's IP address */
#define SERVER_PORT 5566              /* Server's port number */
#define BUF_SIZE    1024              /* Size of buffer used for data transmission */

static int client_fd;                  /* Client socket file descriptor */
static struct sockaddr_in server_addr; /* Server socket address struct */

static void client_init() {
    /* Creates a client socket descriptor */
    client_fd = socket(AF_INET, SOCK_STREAM, 0);

    /* Handles socket error */
    if (client_fd == -1) {
        perror("socket error");
        exit(errno);
    }

    /* Sets fields of Server socket address struct */
    server_addr.sin_family = AF_INET;                   /* Protocol family (IPv4) */
    server_addr.sin_port = SERVER_PORT;                 /* Port number in network byte order (big-endian) */
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP); /* IP address in network byte order (big-endian) */

    /* Establishes a connection to the server and handles connect error */
    if (connect(client_fd, (struct sockaddr *)(&server_addr), sizeof(server_addr)) == -1) {
        perror("connect error");
        exit(errno);
    }
}

void main() {
    FILE *file;
    char buffer[BUF_SIZE];

    file = fopen("./client.txt", "r+");

    if (file == NULL) {
        perror("fopen error");
        exit(errno);
    }

    client_init();

    while (fgets(buffer, BUF_SIZE, file) != NULL) {
        // Sends data to the server and handles sendto error
        if (sendto(client_fd, buffer, BUF_SIZE, 0, (struct sockaddr *)(&server_addr), sizeof(server_addr))== -1) {
            perror("sendto error");
            exit(1);
        }

        // Clears buffer
        bzero(buffer, BUF_SIZE);
    }

    fclose(file);
}

TCP server code (in Python)

import socket
import threading

SERVER_IP     = "127.0.0.1"
SERVER_PORT   = 5566
SERVER_ADDR   = (SERVER_IP, SERVER_PORT)
PACKET_SIZE   = 1024

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server.bind(SERVER_ADDR)


def client_handler(client, client_addr):
    print(f"[NEW CONNECTION] {client_addr}\n")

    while True:
        # Reads at most PACKET_SIZE bytes data, blocks when no packet is received
        packet = client.recv(PACKET_SIZE)

        # Writes file from the packet received
        with open('./server.txt', 'wb') as file:
            file.write(packet)

def server_init():
    print(f"Listening on {SERVER_PORT}")
    server.listen()
    
    while True:
        # Everytime a new client is connected to the server, create a new thread dedicated to that client
        # Every thread will block until the connection to that client is established
        client, client_addr = server.accept()
        thread = threading.Thread(target=client_handler, args=(client, client_addr))
        thread.start()
        print(f"[ACTIVE CONNECTION] {threading.active_count() - 1}\n")


print("Starting server...")
server_init()

Solution

  • All Unix-style socket networking code uses what is known as "network byte order", which is also known as "big-endian". But many common desktop/embedded platforms (e.g. x86 and ARM) use "little-endian" byte ordering.

    When you set up a socket in your C code, you need to convert your port number from the native, little-endian, "host" byte order, to "network" order. To do that, you can use the htons() function, which is a shortening of host-to-network-short().

    i.e. you want this:

    server_addr.sin_port = htons(SERVER_PORT);
    

    It seems that the python sockets library handles this kind of thing under the hood, so you don't need to worry about it there.