2

I'm trying to get a C Client to connect to a Python server in UNIX/Linux. However, it seems my C Client isn't able to connect to the Python server. I tried running on the localhost, but that didn't seem to work. Hard-coding the hostnames into both the server and the client (to "127.0.0.1") didn't work either.

Here's the code for the Python server:

import socket
import sys

HOST = "127.0.0.1"
PORT = 8888

print("creating socket...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print("binding socket...")
try:
    s.bind((HOST, PORT))
except socket.error as err:
    print("error binding socket, {}, {}".format(err[0], err[1]))
print("successfully bound socket")

s.listen(1)
print("now listening on {}:{}".format(HOST, PORT))

while True:
    conn, addr = s.accept()
    conn.sendall(str.encode("testing"))
    #conn.close()

s.close()

...and here's the code for the C Client:

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

int main(int argc, char** argv) {
    if (argc != 3) {
        printf("usage: client [HOSTNAME] [PORT]\n");
        return 0;
    }

    const char *hostname = argv[1];
    int port = atoi(argv[2]);

    int sockfd = 0, n = 0;
    char recvBuff[1024];
    struct sockaddr_in saddr;

    memset(recvBuff, '0', sizeof(recvBuff));
    if ( sockfd = socket(AF_INET, SOCK_STREAM, 0) < 0 ) {
        fprintf(stderr, "error: could not create socket\n");
        return 1;
    }

    saddr.sin_family = AF_INET;
    saddr.sin_port   = htons(port);
    saddr.sin_addr.s_addr = htonl(hostname);

    if ( connect(sockfd, (struct sockaddr_in*)&saddr, sizeof(saddr)) < 0 ) {
        fprintf(stderr, "error: could not connect to %s:%i\n", hostname, port);
        return 1;
    }

    while ( n = read(sockfd, recvBuff, sizeof(recvBuff) - 1) > 0 ) {
        recvBuff[n] = 0;
        if ( fputs(recvBuff, stdout) == "EOF" ) {
            fprintf(stderr, "error: fputs\n");
        }

        printf("\n");
    }

    return 0;
}

Interestingly enough, I can still connect to the Python server via other means, like telnet, or through this client coded in Python:

import socket
import sys

HOST = "localhost"
PORT = 8888

print("creating socket")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

print("attempting to connect to host")
try:
    s.connect((HOST, PORT))
except socket.error as err:
    print("error: could not connect to host, {}, {}".format(err[0], err[1]))
    sys.exit()

print("successfully connected to host")

data = s.recv(1024)
s.close()

print("The server responded with: {}".format(data))

I assume this is a client-side issue, then, since other methods to connecting to the server seems to work just fine. If that is the case, how would I go about fixing the C Code to connect properly? If that is not the case, could this be an issue pertaining to my network? I tried running in both an Arch VM and my school's IT Servers, and both yielded the same result.

3
  • What does happen when your C client "doesn't work"? Commented Oct 6, 2017 at 13:45
  • Have you tried running your client in a debugger to see what it's doing? Commented Oct 6, 2017 at 13:47
  • The C Client fails to connect. It stops at "error: could not connect to [host]", and simply exits. I assume this means the client simply failed to connect to the server. And no, I haven't run the client in a debugger as of yet. Commented Oct 6, 2017 at 13:56

2 Answers 2

3

Your C client incorrectly sets the address to (try to) connect to. In fact, given that variable hostname is a char * pointing to one of the program arguments, this is completely wrong:

saddr.sin_addr.s_addr = htonl(hostname);

Your compiler should be emitting warnings about it; if not, then either turn up the warning level or get a better compiler. htonl() expects a 32-bit unsigned integer as its argument. A pointer can be converted to that type (though not without a cast, except as an extension), but that converts the pointer itself, not the data to which it points.

You need to convert the provided string-form address to numeric form, and assign that to your socket address. Provided that you are willing to rely on the "hostname" to in fact be formatted as a dotted-quad IPv4 address, you can instead do this:

int result = inet_pton(AF_INET, hostname, &saddr.sin_addr);

Do not neglect to check the return value, and be aware that it employs an unusual convention: you're looking for it to return 1 (not 0) if the conversion is successful.

If you want to accept domain names as well as dotted-quad addresses then you will need to engage the resolver to help you choose an appropriate destination address based on the program argument. The getaddrinfo() function is your best entry there, but do carefully read the (linked) docs, as there are some potential gotchas.

Sign up to request clarification or add additional context in comments.

Comments

1

If you check the manual of htonl it will say htonl(uint32_t hostlong);.

You're passing as argument a string, hoping that it's converted to the correct uint32 format. That's not going to happen.

You can use for example

hostinfo = gethostbyname (hostname);
saddr->sin_addr = *(struct in_addr *) hostinfo->h_addr;

1 Comment

+1 for an accurate answer, but do take note of these leading comments from the Linux manual page of gethostbyname(): "The gethostbyname*() and gethostbyaddr*() functions are obsolete. Applications should use getaddrinfo(3) and getnameinfo(3) instead."

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.