【问题标题】:Multiple Socket Connections for File Transfer用于文件传输的多个套接字连接
【发布时间】:2014-11-22 05:25:08
【问题描述】:

我正在开发一个基于 TCP 的文件传输程序,该程序在带有套接字的 Unix 上运行。我需要创建一个程序来打开两个单独的数据连接,类似于 FTP 协议。一个连接用于客户端和服务器相互发送命令,另一个用于实际传输文件中的字节。换句话说,有一个客户端,一个服务器,它们之间有两个连接。

我在不同的端口上创建了两个套接字连接——主机是相同的。例如,命令连接为 127.0.0.1:6000,IO 连接为 127:0.0.1:6005。

服务器:

if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
    perror ("Can't create a socket");
    exit(1);
}

bzero((char *)&server, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(6005);
server.sin_addr.s_addr = htonl(INADDR_ANY); 

if (bind(socket_fd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
    perror("Can't bind name to socket");
    exit(1);
}

listen(socket_fd, 10);

while (TRUE)
{
    client_len= sizeof(client);
    if ((connect_fd = accept (socket_fd, (struct sockaddr *)&client, &client_len)) == -1)
    {
        fprintf(stderr, "Can't accept client\n");
        exit(1);
    }

    printf(" Remote Address:  %s\n", inet_ntoa(client.sin_addr));
    temp = buffer;
    num_bytes = BUFLEN;
    while ((n = recv (connect_fd, temp, num_bytes, 0)) < BUFLEN)
    {
        temp += n;
        num_bytes -= n;
    }

    if(strncmp("SEND", buffer, 4) == 0)
    {
        printf("Client Sending Data...\n");

        // setup server type socket for the file transfer data connection 
        struct sockaddr_in data_conn, data_client;
        int conn_fd, new_conn_fd, data_client_len; 
        char *filename;

        if((conn_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        {
            perror("Cannot Create Data Connection Socket!\n");
            exit(1);
        }

        // populate data connection socket 
        bzero((char *)&data_conn, sizeof(struct sockaddr_in));
        data_conn.sin_family = AF_INET;
        data_conn.sin_port = htons(6000);
        data_conn.sin_addr.s_addr = htonl(INADDR_ANY);

        // bind the new data connection socket 
        if (bind(conn_fd, (struct sockaddr *)&data_conn, sizeof(data_conn)) == -1)
        {
            perror("Can't Bind Name to Data Connection Socket!\n");
            exit(1);
        }

        listen(conn_fd, 5);             

        bzero(temp, BUFLEN);
        bzero(buffer, BUFLEN);

        temp = buffer;
                num_bytes = BUFLEN;
                while ((n = recv (connect_fd, temp, num_bytes, 0)) < BUFLEN)
                {
                        temp += n;
                        num_bytes -= n;
                }       

        fprintf(stdout, "Receiving File: %s\n", buffer);

        FILE *fp;
        fp = fopen(buffer, "w");
        if(fp == NULL)
        {
            perror("Could not open destination file\n");
            exit(1);
        }

        data_client_len= sizeof(data_client);
        if ((new_conn_fd = accept (conn_fd, (struct sockaddr *)&data_client, &data_client_len)) == -1)
        {
            fprintf(stderr, "Can't accept data connection client\n");
            exit(1);
        }

        bzero(temp, BUFLEN);
        bzero(buffer, BUFLEN);

 temp = buffer;
  num_bytes = BUFLEN;

        printf("foo\n"); // this prints! so issue must be below
        while ((n = recv (new_conn_fd, temp, num_bytes, 0)) < BUFLEN)
        {
                    temp += n;
                    num_bytes -= n;
        }

        // just printing the file contents for now 
        fprintf(stdout, "received file contents: %s\n", buffer);

        fclose(fp);         

    }   
    else if(strncmp("GET", buffer, 3) == 0)
    {

      // get stuff not implemented yet 
    }
    else
    {
        perror("Client Issued an Invalid Command\n");
        exit(1);
    }   

    close (connect_fd);
}
close(socket_fd);
return(0);

客户:

// first check to make sure that the FTP command was either GET or SET
if(strncmp("GET", command, 3) == 0)
{
    operation = GET;
}
else if (strncmp("SEND", command, 4) == 0)
{
    operation = SEND;
}
else
{
    perror("The command must be either GET or SET (case sensitive)\n");
    exit(1);
}

// Create the socket
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
    perror("Cannot create socket");
    exit(1);
}

bzero((char *)&server, sizeof(struct sockaddr_in));
server.sin_family = AF_INET;
server.sin_port = htons(port);

if ((host_info = gethostbyname(host)) == NULL)
{
    fprintf(stderr, "Unknown server address\n");
    exit(1);
}

bcopy(host_info->h_addr, (char *)&server.sin_addr, host_info->h_length);

// Connecting to the server
if (connect (socket_fd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
    fprintf(stderr, "Can't connect to server\n");
    perror("connect");
    exit(1);
}

printf("Connected:\n");
    printf("\t\tServer Name: %s\n", host_info->h_name);
pptr = host_info->h_addr_list;
printf("\t\tIP Address: %s\n", inet_ntop(host_info->h_addrtype, *pptr, str, sizeof(str)));


if(operation == SEND)
{
    bzero(send_buffer, BUFLEN); 
    strcpy(send_buffer, "SEND");
    send (socket_fd, send_buffer, BUFLEN, 0);       

    // send the filename to the server
    bzero(send_buffer, BUFLEN);
    strcpy(send_buffer, filename);
    send(socket_fd, send_buffer, BUFLEN, 0);        


    // read the files contents 
    FILE *fp;
    fp = fopen(filename, "r");

    if(fp == NULL)
    {
        fprintf(stderr, "File '%s' is invalid! Please choose a valid filename\n", filename); 
        exit(1);        
    }

    fseek(fp, 0, SEEK_END);
    long fsize = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    char *string = malloc(fsize+1);
    fread(string, fsize, 1, fp);

    string[fsize] = 0;

    struct sockaddr_in data_conn;
    int data_conn_fd;

    // establish a client connection on port 6000 
    if ((data_conn_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {   
        perror("Cannot create data connection socket");
        exit(1);
    }

    bzero((char *)&data_conn, sizeof(struct sockaddr_in));

    data_conn.sin_family = AF_INET;
    data_conn.sin_port = htons(6000);
    bcopy(host_info->h_addr, (char *)&data_conn.sin_addr, host_info->h_length);

    if (connect (data_conn_fd, (struct sockaddr *)&data_conn, sizeof(data_conn)) == -1)
    {
        fprintf(stderr, "Can't connect to data connection server\n");
        exit(1);
    }


    send(data_conn_fd, string, fsize, 0);

    fclose(fp);
    //close(data_conn_fd);


}
else if (operation == GET)
{
    // not yet implemented 
}
else
{
    perror("Invalid Operation!\n");
    exit(1); 
}   

fflush(stdout);
close (socket_fd);
return (0);
}

该程序具有向服务器发送文件和从服务器接收文件的功能。我现在只实现了发送功能。

程序挂起的服务器代码接近尾声。我将文件内容打印到标准输出的地方。我这样做是为了测试,因为将其转储到文件中是微不足道的。我使用了 printf(“foo”) 打印但之后挂起。客户端中 send() 对应的 while 循环似乎不起作用。它在打印声明之后挂起。其余的似乎正在工作。

另请注意,我不能使用双连接。

任何帮助或建议将不胜感激。

【问题讨论】:

  • 刚刚注意到这一点,你认为这是做什么的:while ((n = recv (connect_fd, temp, num_bytes, 0)) &lt; BUFLEN) when/if recv() fails(即返回-1)?您是否看到循环退出的任何方式?

标签: c linux sockets tcp posix


【解决方案1】:

接收循环不包括recv()没有传输任何数据的两种情况。

有:

  1. 检测到错误并返回-1
  2. 检测到连接已关闭并返回0

send() 的调用完全忽略返回的值。不要这样做,因为

  1. 还有send() 可能无法返回-1
  2. send() 也可能返回发送的数据比通知发送的数据少。代码将围绕send() 循环并计数,直到所有数据都发送出去。

【讨论】:

  • 在阻塞模式下,send() 会阻塞,直到所有数据都传输完毕。
  • 好的,谢谢!这是我的问题的一部分。当我发送数据时,我被称为 send(),大小为 fsize,但接收者期望大小为 BUFLEN,所以它被阻塞了,正如你所说,我的代码没有检查它。我把所有的 fsize 都改成了 BUFLEN 并且成功了!
猜你喜欢
  • 2020-12-02
  • 1970-01-01
  • 2013-06-26
  • 1970-01-01
相关资源
最近更新 更多