用于文件传输的多个套接字连接

时间:2014-09-27 07:38:35

标签: c linux sockets tcp posix

我正在研究基于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);
}

该程序具有将文件发送到服务器并从服务器接收文件的功能。我现在只实现了send函数。

在服务器代码结束时,程序挂起。我正在将文件内容打印到stdout的点。我这样做是为了测试将其转储到文件中是微不足道的。我使用了printf(“foo”)进行打印,但之后会挂起。似乎对应于客户端中的send()的while循环不起作用。它是在那份印刷声明之后悬挂的。其余的似乎工作。

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

非常感谢任何帮助或建议。

1 个答案:

答案 0 :(得分:1)

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

正如:

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

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

    1. send()也可能无法返回-1
    2. 同样send()可能会返回发送的数据少于发送的数据。代码应循环send()并计数直到所有数据都已发送出去。