2017-10-06 15 views
2

我试图让C客户端连接到UNIX/Linux中的Python服务器。但是,似乎我的C客户端无法连接到Python服务器。我尝试在本地主机上运行,​​但似乎没有工作。 将主机名硬编码到服务器和客户端(至“127.0.0.1”)也不起作用。UNIX套接字编程:获取C客户端连接到Python服务器的问题

下面是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代码连接问题?如果情况并非如此,这可能是与我的网络有关的问题吗?我试着在Arch VM和我的学校的IT服务器上运行,并且都取得了相同的结果。

+0

当你的C客户端“不工作”时会发生什么? –

+0

您是否尝试过在调试器中运行客户端以查看它在做什么? –

+0

C客户端无法连接。它停在“错误:无法连接到[主机]”,并退出。我认为这意味着客户端只是无法连接到服务器。不,我还没有在调试器中运行客户端。 –

回答

1

如果您查看htonl的手册,它会显示htonl(uint32_t hostlong);

您正在传递一个字符串参数,希望它被转换为正确的uint32格式。这不会发生。

可以使用例如

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

+1以获得准确的答案,但请注意以下来自'gethostbyname()'的Linux手册页的这些主要评论:“'gethostbyname *'()和'gethostbyaddr *'()函数已过时。而是使用getaddrinfo(3)和getnameinfo(3)。“ –

3

您的C客户端错误地设置地址(尝试)连接。事实上,由于变量hostnamechar *指向的程序的参数之一,这是完全错误的:

saddr.sin_addr.s_addr = htonl(hostname); 

你的编译器应该发出关于它的警告;如果没有,那么或者调高警戒级别或者获得更好的编译器。 htonl()需要一个32位无符号整数作为其参数。指针可以转换为该类型(尽管不是没有强制转换,除了作为扩展名),但指针本身转换为,而不是指向的数据。

您需要将提供的字符串表单地址转换为数字形式,并将指定为到您的套接字地址。只要你愿意依靠“主机名”在事实上被格式化为一个点分四组IPv4地址,可以改为做到这一点:

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

不要忽略检查返回值,并注意它使用了一种不寻常的约定:如果转换成功,您正在寻找它返回1(而不是0)。

如果您想接受域名以及虚线地址,那么您需要启用解析器来帮助您根据程序参数选择适当的目标地址。 getaddrinfo()功能是你最好的入门,但仔细阅读(链接)的文档,因为有一些潜在的问题。

相关问题