简体   繁体   English

UNIX套接字编程:获取C客户端连接到Python服务器的问题

[英]UNIX Socket Programming: Issues Getting a C Client to Connect to a Python Server

I'm trying to get a C Client to connect to a Python server in UNIX/Linux. 我正在尝试让C客户端连接到UNIX / Linux中的Python服务器。 However, it seems my C Client isn't able to connect to the Python server. 但是,看来我的C客户端无法连接到Python服务器。 I tried running on the localhost, but that didn't seem to work. 我尝试在localhost上运行,但这似乎不起作用。 Hard-coding the hostnames into both the server and the client (to "127.0.0.1") didn't work either. 将主机名硬编码到服务器和客户端中(分别为“ 127.0.0.1”)也不起作用。

Here's the code for the Python server: 这是Python服务器的代码:

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: ...这是C客户端的代码:

#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: 有趣的是,我仍然可以通过其他方式(例如telnet)或通过此Python编码的客户端连接到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? 如果是这种情况,我将如何修复C代码以正确连接? 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. 我尝试同时在Arch VM和学校的IT服务器中运行,并且都得到了相同的结果。

Your C client incorrectly sets the address to (try to) connect to. 您的C客户端错误地将地址设置为(尝试连接)。 In fact, given that variable hostname is a char * pointing to one of the program arguments, this is completely wrong: 实际上,鉴于变量hostname是指向程序参数之一的char * ,这是完全错误的:

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. htonl()需要一个32位无符号整数作为其参数。 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: 如果您愿意依靠“主机名”来将其格式化为点分四进制的IPv4地址,则可以执行以下操作:

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. 不要忽略检查返回值,并且要注意它采用了一种不同寻常的约定:如果转换成功,您正在寻找返回的值是1(不是0)。

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. getaddrinfo()函数是您最好的选择,但是仔细阅读(链接的)文档,因为这有一些潜在的陷阱。

If you check the manual of htonl it will say htonl(uint32_t hostlong); 如果您查看了htonl的手册,它将显示htonl(uint32_t hostlong); .

You're passing as argument a string, hoping that it's converted to the correct uint32 format. 您正在传递一个字符串作为参数,希望将其转换为正确的uint32格式。 That's not going to happen. 那不会发生。

You can use for example 您可以使用例如

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM