UNIX套接字编程:让C客户机连接到Python的问题

2024-06-30 05:15:57 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试让一个C客户机连接到UNIX/Linux中的Python服务器。但是,我的C客户机似乎无法连接到Python服务器。我试着在本地主机上运行,但似乎不起作用。将主机名硬编码到服务器和客户端(到“127.0.0.1”)也不起作用。

下面是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()

…下面是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;
}

有趣的是,我仍然可以通过其他方式连接到Python服务器,比如telnet,或者通过这个用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))

我假设这是一个客户端问题,因为连接到服务器的其他方法似乎可以正常工作。如果是这样的话,我将如何着手修复C代码以正确连接?如果不是这样的话,这可能是一个与我的网络有关的问题吗?我试着在ArchVM和学校的IT服务器上运行,结果都是一样的。你知道吗


Tags: toimport服务器hostincludeportconnectsys
2条回答

如果你查看htonl的手册,它会说htonl(uint32_t hostlong);。你知道吗

您正在传递一个字符串作为参数,希望它被转换成正确的uint32格式。那不会发生的。你知道吗

例如,您可以使用

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

您的C客户端错误地设置了要(尝试)连接到的地址。事实上,假设变量hostname是指向某个程序参数的char *,这是完全错误的:

saddr.sin_addr.s_addr = htonl(hostname);

你的编译器应该发出关于它的警告;如果没有,那么要么提高警告级别,要么找一个更好的编译器。htonl()需要一个32位无符号整数作为其参数。指针可以转换为该类型(虽然不是没有强制转换,而是作为扩展名),但是它转换的是指针本身,而不是它所指向的数据。你知道吗

您需要将提供的字符串形式地址转换为数字形式,并将指定给套接字地址。如果您愿意依赖“主机名”实际格式化为虚线四元IPv4地址,则可以执行以下操作:

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

不要忽略检查返回值,要注意它采用了一种不寻常的约定:如果转换成功,您希望它返回1(而不是0)。你知道吗

如果您想接受域名以及虚线四元地址,那么您需要使用解析器来帮助您根据程序参数选择适当的目标地址。^{}函数是您最好的入口,但是请仔细阅读(链接的)文档,因为其中有一些潜在的问题。你知道吗

相关问题 更多 >