【问题标题】:Server and client in Python and CPython 和 C 中的服务器和客户端
【发布时间】:2013-11-25 16:24:35
【问题描述】:

我用 python 编写了一个简单的客户端代码,我正在尝试连接到一个用 C 编写的简单的回显服务器。

我知道没关系,但由于某种原因,我确实设法连接到用 python 编写的服务器,但我无法连接到 C 服务器。

这是客户端的代码:

import socket
import sys
import time

HOST = 'localhost'   
PORT = 11000             
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
msg = raw_input()
s.send(msg)
data = s.recv(len(msg))
s.close()
print 'Received: ', data

这是回显服务器的 C 代码:

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

#ifndef AF_INET
#define AF_INET 2
#endif

#ifndef SOCK_DGRAM
#define SOCK_DGRAM 2
#endif

#ifndef INADDR_ANY
#define INADDR_ANY 0
#endif

#ifndef IP_DONTFRAG
#define IP_DONTFRAG     67
#endif

#define BUFFER_SIZE 1024

#define ECHO_PORT_UDP 10000
#define ECHO_PORT_TCP 11000

int main(int argc, char *argv[]) {
    int echo_socket = 0;
    int echo_socket_child = 0; // for TCP
    struct sockaddr_in server;
    struct sockaddr_in client;
    struct hostent *hostp; // client host info
    struct sockaddr_in clientaddr; // client addr
    char *hostaddrp; // dotted decimal host addr string
    char buffer[BUFFER_SIZE];
    unsigned int clientlen = 0;
    unsigned int serverlen = 0;
    int received = 0;
    int port = 0;
    char *endptr;
    int optval = 1;
    int msg_byte_size = 0;


// Parameters check
    if (argc == 2) {
        port = strtol(argv[1], &endptr, 0);
        if ((*endptr) || ((port != ECHO_PORT_UDP) && (port != ECHO_PORT_TCP)))  {
        printf("EchoServer: Invalid port number.\n Use port %d for UDP, port %d for TCP.\n", ECHO_PORT_UDP, ECHO_PORT_TCP);
            return -1;
        }
        else {
            if (port == ECHO_PORT_UDP) {
                printf("EchoServer: Running UDP on port %d.\n", port);
            }
            if (port == ECHO_PORT_TCP) {
                printf("EchoServer: Running TCP on port %d.\n", port);
            }
        }
    }
    else {
        printf("EchoServer: Invalid arguments.\n");
        return -1;
    }


// Opening UDP socket
    if (port == ECHO_PORT_UDP) {
        if ((echo_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
            printf("EchoServer: Failed opening socket");
            return -1;
        }

    }
    if (port == ECHO_PORT_TCP) {
        if ((echo_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            printf("EchoServer: Failed opening socket");
            return -1;
        }

        // setsockopt: Handy debugging trick that lets  us rerun the server immediately after we kill it; otherwise we have to wait about 20 secs.
        // Eliminates "ERROR on binding: Address already in use" error.
        setsockopt(echo_socket, SOL_SOCKET, SO_REUSEADDR,(const void *)&optval , sizeof(int));

    }

// Construct the server sockaddr_in structure
    memset(&server, 0, sizeof(server));             /* Clear struct */
    server.sin_family = AF_INET;                    /* Internet/IP */
    server.sin_addr.s_addr = htonl(INADDR_ANY);     /* Any IP address */
    server.sin_port = htons(atol(argv[1]));         /* server port */

// Bind the socket
    serverlen = sizeof(server);
    if (bind(echo_socket, (struct sockaddr *) &server, serverlen) < 0) {
        printf("EchoServer: Failed binding socket");
        return -1;
}    


// Wait for a datagram until cancelled
if (port == ECHO_PORT_UDP) {
    while (1) {
        /* Receive a message from the client */
        clientlen = sizeof(client);
        if ((received = recvfrom(echo_socket, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client, &clientlen)) < 0) {

            printf("EchoServer: Failed receiving datagram");
            return -1;
        }
        printf("Client datagram received from: %s\n", inet_ntoa(client.sin_addr));
        /* Send the message back to client */
        if (sendto(echo_socket, buffer, received, 0, (struct sockaddr *) &client, sizeof(client)) != received) {
            printf("Mismatch in number of echoed bytes");
            return -1;
        }
    }
}

// Wait for a connection until cancelled
if (port == ECHO_PORT_TCP) {
    while (1) {
        echo_socket_child = accept(echo_socket, (struct sockaddr *) &client, &clientlen);
        if (echo_socket_child < 0) {
            printf("ERROR on accept");
            break;
        }

        // gethostbyaddr: determine who sent the message
        hostp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr, sizeof(clientaddr.sin_addr.s_addr), AF_INET);
        if (hostp == NULL) {
            printf("ERROR on gethostbyaddr");
            break;
        }
        hostaddrp = inet_ntoa(clientaddr.sin_addr);
        if (hostaddrp == NULL) {
            printf("ERROR on inet_ntoa\n");
            break;
        }
        printf("server established connection with %s \n", hostaddrp);

        // read: read input string from the client
        bzero(buffer, BUFFER_SIZE);
        msg_byte_size = read(echo_socket_child, buffer, BUFFER_SIZE);
        if (msg_byte_size < 0) {
            printf("ERROR reading from socket");
            break;
        }
        printf("server received %d bytes: %s", msg_byte_size, buffer);

        // write: echo the input string back to the client
        msg_byte_size = write(echo_socket_child, buffer, strlen(buffer));
        if (msg_byte_size < 0) {
            printf("ERROR writing to socket");
            break;
        }
    } // endof while(1)
    close(echo_socket_child);
    return -1;
}
return 0;

}

任何想法为什么我无法连接到服务器?

编辑: 这是我收到的错误:

Traceback (most recent call last):
  File "s.py", line 8, in <module>
    s.connect((HOST, PORT))
  File "C:\Python27\lib\socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 10061]

【问题讨论】:

  • 你为什么要定义所有这些常量?
  • 这个服务器不是我写的,而是把它当成一个黑匣子来用的。
  • python 客户端报告连接失败的原因是什么?
  • 运行服务器后,它是否显示为在netstat -a 下监听?如果没有,我会调试 c++ 直到它完成。
  • 不,我真的没有看到任何来自端口 11000 正在监听的东西。你看到服务器有问题吗?

标签: c++ python c client-server


【解决方案1】:

(1) 将listen 调用添加到代码的 TCP 部分。

(2) 你必须告诉accept 你传递的 sockaddr 的长度是多少,它会反过来告诉你它返回的客户端地址的长度。您将其作为 0 长度传递,因此它自然不会传回客户端地址,这随后使您的 gethostbyaddr 因未知地址而失败。

(3) 如果您不在循环内关闭客户端套接字,它只会在服务器生命周期内保持打开状态(并泄漏文件描述符)。最终你会用完 FD。它不会影响您的客户端,它会在收到一条消息后关闭,但任何写入多条消息的客户端都不会被服务器接收到,也永远不会收到来自服务器的 eof。

if (port == ECHO_PORT_TCP)
{
    if (listen(echo_socket, ECHO_PORT_TCP) == -1)
    {
        perror("listen");
        exit(1);
    }

    while (1)
    {
        clientlen = sizeof(client);

        echo_socket_child = accept(echo_socket, (struct sockaddr *) &client, &clientlen);

        if (echo_socket_child < 0)
        {
              perror("accept"); 
              break; 
        }

        // gethostbyaddr: determine who sent the message
        hostp = gethostbyaddr((const char *) &client.sin_addr.s_addr, sizeof(client.sin_addr.s_addr), AF_INET);

        if (hostp == NULL)
        {   herror("byaddr"); 
            break;
        }

        hostaddrp = inet_ntoa(client.sin_addr);

        if (hostaddrp == NULL)
        {
            printf("ERROR on inet_ntoa\n");
            break;
        }

        printf("server established connection with %s (%s)\n", hostp->h_name, hostaddrp);

        bzero(buffer, BUFFER_SIZE);
        msg_byte_size = read(echo_socket_child, buffer, BUFFER_SIZE);

        if (msg_byte_size < 0)
        {
            printf("ERROR reading from socket");
            break;
        }

        printf("server received %d bytes: %s", msg_byte_size, buffer);

        msg_byte_size = write(echo_socket_child, buffer, strlen(buffer));

        if (msg_byte_size < 0)
        {
            printf("ERROR writing to socket");
            break;
        }

        close(echo_socket_child);

    } // endof while(1)

    return -1;
}

【讨论】:

  • 好的,在服务器中添加监听部分后,我到达了发送消息的位置,但是在发送消息后,它在客户端和服务器上都崩溃了。客户端错误:回溯(最近一次调用最后一次):文件“s.py”,第 11 行,在 data = s.recv(len(msg)) socket.error: [Errno 10054] 和服务器上的错误: gethostbyaddr 上的错误 P.S 为什么要在循环内添加关闭,而不是将其留在外面?
  • @Jjang,我修改了答案。
猜你喜欢
  • 2016-01-05
  • 2013-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-24
  • 1970-01-01
  • 2020-11-28
  • 1970-01-01
相关资源
最近更新 更多