3

我正在创建一个客户端-服务器程序。服务器向客户端发送一个数字范围,客户端对该范围进行操作(找到完美数字)并返回结果。服务器用 Python 编写,客户端用 C 编写。这是我的代码:

服务器(Python):

import socket

def SendRequestToCompute():
    # Server-side
    SERV_IP = '--some ip--'
    # Port
    SERV_PORT = --some port--

    # Create socket
    serv_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    serv_socket.connect((SERV_IP, SERV_PORT))
    serv_socket.sendall('100')
    serv_socket.close()

def ReceiveRequestFromCompute():
    # Server-side: all available resources
    SERV_IP = ''
    SERV_PORT = 2890
    # Create and bind the sockets
    serv_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # Make the socket "reusable" for further tries
    serv_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    serv_socket.bind((SERV_IP, SERV_PORT))
    serv_socket.listen(1)

    # Accept the connection and block until a socket is received
    client_conn, client_addr = serv_socket.accept()

    print 'Connection established: ', client_addr
    while 1:
        data = client_conn.recv(1024)

        # Get the string of numbers
        joint_string = repr(data)
        # get rid of the ' character at the begining and end caused by repr()
        joint_string = joint_string[1:]

        return joint_string

        # break out of the while loop once all the numbers were recieved
        break   
        if not data: break
    client_conn.close()

def SendNumbersToReport(results):
    # Server-side
    SERV_IP = --some ip--
    # port
    SERV_PORT = --some port-

    # Create socket
    serv_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    serv_socket.connect((SERV_IP, SERV_PORT))
    serv_socket.sendall(results)
    data = serv_socket.recv(3)
    serv_socket.close()

def main():

    print 'Sending a range of numbers to compute to work on.'
    # Send a request to compute
    SendRequestToCompute()

    print 'Waiting to get the results from compute...'
    # Receive the results from compute
    results = ReceiveRequestFromCompute()

    print 'Sending numbers to report to print...'
    #Send the numbers to report for printing
    SendNumbersToReport(results)


if __name__ == "__main__": main()

客户 (C):

#include    <sys/types.h>   
#include    <sys/socket.h>
#include    <sys/time.h>    
#include    <time.h>        
#include    <netinet/in.h>  
#include    <arpa/inet.h>   
#include    <errno.h>
#include    <fcntl.h>       
#include    <netdb.h>
#include    <signal.h>
#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include <strings.h>     
#include    <sys/stat.h>    
#include    <sys/uio.h> 
#include    <unistd.h>
#include    <sys/wait.h>
#include    <sys/select.h>
#include <pthread.h>

#define MAXLINE 4096    /* max text line length */
#define MAXSOCKADDR 128 /* max socket address structure size */
#define BUFFSIZE    8192    /* buffer size for reads and writes */

#define SERV_PORT_REQUEST 2891 /* The port number to get request from compute */
#define SERV_PORT        --port number--
#define SERV_IP "--some ip--" /* IP address */

long range = 0;

// The global variable to hold the numbers
char *strnumbers;

// Function prototypes
void *ThreadWorker(void *threadId);

int main(int argc, char **argv){
    int i;
    int sockfd;
    ssize_t n;
    struct sockaddr_in cliaddr;
    struct sockaddr_in  servaddr;
    socklen_t clilen;
    char sendline[MAXLINE];
    char recvline[MAXLINE];
    char buffer[MAXLINE];
    int listenfd;
    pthread_t thread;
    void *status;

    // Initialize the strnumbers array
    strnumbers = (char *) malloc (100 * sizeof(char));

    // Get the range of numbers from the server to work on
    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT_REQUEST);

    // General information for the user
    printf("Waiting to recieve a request from the server (manage)...\n");

    // Bind the socket and start listening for the peer socket
    bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
    listen(listenfd, 1);

    clilen = sizeof(cliaddr);
    sockfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);

    bzero(buffer, MAXLINE);

    if((n = read(sockfd, buffer, MAXLINE)) == 0){
        //connection closed by client
        close(sockfd);
    }else{
        // Convert the received range (string) to integer
        range = atoi(buffer);
        close(sockfd);
    }

    printf("Request received: Working on %lld numbers.\n", range);

    // Create the thread to find the perfect numbers
    if((pthread_create(&thread, NULL, ThreadWorker, (void *)0)) != 0){
        perror("Failed to create a thread.\n");
        exit(-1);
    }

    // Wait for the thread to finish its job
    pthread_join(thread, &status);

    // Create the socket to send the the results with
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    inet_pton(AF_INET, SERV_IP, &servaddr.sin_addr);

    // Connect to the created socket
    if((connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))) != 0){
      perror("Unable to connect to the server - make sure the server is up and running.");
      exit(-1);
    }

    // Send the numbers via the socket
    write(sockfd, strnumbers, 100);

    // Close the socket
    close(sockfd);

    exit(0);
}

void *ThreadWorker(void *threadId)
{
  long long total = 0;
  long long sum = 0;
  long long num;
  long long j;

  char buffer[30];

  // Brute-force algorithm to find the perfect numbers that will take approximately 15 seconds
  for(num = 1; num < range; num++){
    sum = 0;
    for(j = 1; j < num; j++){
      if((num % j) == 0){
        sum+=j;
      }
    }

    if(sum == num){
      // Convert the long number to string
      snprintf(buffer, 10, "%lld", sum);
      // Concatenate the string to the strnumbers array
      strcat(strnumbers, buffer);
      // Add a special character at the end of the each number to differentiate each number
      strcat(strnumbers, "/");
    }

  } 

    pthread_exit(NULL);
}

该程序在第一次运行时运行良好,但在运行两次或多次后,服务器会抛出一个异常,提示:socket.error: [Errno 111] Connection refused尝试向客户端发送一系列数字时。我有一种感觉,也许我没有适当地关闭连接,但我无法弄清楚我做错了什么。任何帮助,将不胜感激。

4

1 回答 1

4

两个程序之间不需要多个 TCP 连接,一个就足够了,因为它是全双工的。

我建议您让您的生活更轻松,并遵循公认的客户端/服务器设计,其中服务器将其服务器套接字绑定到已知端口,侦听客户端连接,接受并服务它们,而客户端连接到已知地址和端口,然后发送和通过该单个 TCP 连接接收消息(根据您定义的某些应用程序协议)。

于 2012-11-29T04:48:23.633 回答