在套接字客户端服务器中发送多个文件

时间:2017-12-11 21:41:50

标签: c sockets client-server

我想在单个客户端服务器连接上发送多个文件。服务器应接受来自客户端的连接,然后循环访问文件夹并将其中的每个文件发送到客户端。有什么好方法可以让客户端在收到文件后保存每个文件然后正确读取下一个文件。

我有以下服务器代码,只发送1个文件并关闭。

/*
    Server side C/C++ program to demonstrate Socket programming

    compile:
        gcc serverFile.c -o serverFile
    run:
        ./serverFile

    from http://www.geeksforgeeks.org/socket-programming-cc/ 
*/
#include <stdio.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>

#define PORT 8080

int main(int argc, char const *argv[])
{


    char *file_path = "image.jpg";
    int input_file;

    input_file = open(file_path, O_RDONLY);
    if (input_file == -1) {
        exit(EXIT_FAILURE);
    }


    int server_fd, new_socket, valread;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    char *hello = "Hello from server";

    // Creating socket file descriptor. AF_INET is IPv4, SOCK_STREAM is tcp.
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
    {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    //Set socket option (optional?).  SOL_SOCKET is socket level argument.  
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
                                                  &opt, sizeof(opt)))
    {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons( PORT );

    // Forcefully attaching socket to the port 8080
    if (bind(server_fd, (struct sockaddr *)&address, 
                                 sizeof(address))<0)
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    // If you want to read multiple server connections.
    //int x;
    //for (x = 0; x < 3; x++){
    if (listen(server_fd, 3) < 0)
    {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, 
                       (socklen_t*)&addrlen))<0)
    {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    valread = read( new_socket , buffer, 1024);
    printf("%s\n",buffer );

    /*********************** read file and send it over socket ****************************/


    //unsigned char buffer[1000];
    while (1) {
            // Read data into buffer.  We may not have enough to fill up buffer, so we
            // store how many bytes were actually read in bytes_read.
            int bytes_read = read(input_file, buffer, sizeof(buffer));
            if (bytes_read == 0) // We're done reading from the file
                break;

            if (bytes_read < 0) {
                // handle errors
                printf("read error!\n");
            }

            // You need a loop for the write, because not all of the data may be written
            // in one call; write will return how many bytes were written. p keeps
            // track of where in the buffer we are, while we decrement bytes_read
            // to keep track of how many bytes are left to write.
            void *p = buffer;
            while (bytes_read > 0) {
                int bytes_written = write(new_socket, p, bytes_read);
                if (bytes_written <= 0) {
                    // handle errors
                }
                bytes_read -= bytes_written;
                p += bytes_written;
            }
    }

    /***************************************************************************************/

    //send(new_socket , hello , strlen(hello) , 0 );
    //printf("Hello message sent\n");

    close(new_socket);
    close(server_fd);
    //} 
    return 0;
}

1 个答案:

答案 0 :(得分:0)

这就是我提出的,如果有人有任何建设性的批评,我很乐意听到。使用python客户端工作得很好我写了10bytes(filesize),50bytes(文件名)和filesize字节(filedata)。

/*
    Server side C/C++ program to demonstrate Socket programming

    compile:
        gcc serverMultipleFileV2.c -o serverMultipleFileV2
    run:
        ./serverMultipleFileV2

    from http://www.geeksforgeeks.org/socket-programming-cc/ 
*/
#include <stdio.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <stddef.h>
#include <dirent.h>

#define PORT 8080

int main(int argc, char const* argv[])
{

    int server_fd, new_socket, valread;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = { 0 };
    char* hello = "Hello from server";

    // Creating socket file descriptor. AF_INET is IPv4, SOCK_STREAM is tcp.
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    //Set socket option (optional?).  SOL_SOCKET is socket level argument.
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
            &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // Forcefully attaching socket to the port 8080
    if (bind(server_fd, (struct sockaddr*)&address,
            sizeof(address))
        < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    if ((new_socket = accept(server_fd, (struct sockaddr*)&address,
             (socklen_t*)&addrlen))
        < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    valread = read(new_socket, buffer, 1024);
    printf("%s\n", buffer);

    /*********************** read file and send it over socket *************************/

    DIR* dir;
    struct dirent* ent;

    if ((dir = opendir("images/")) == NULL) {
        printf("Couldn't open directory");
        exit(EXIT_FAILURE);
    }

    // loop through folder and read /send all files.
    while ((ent = readdir(dir)) != NULL) {

        if (!strcmp(ent->d_name, ".")) {
            continue;
        }

        if (!strcmp(ent->d_name, "..")) {
            continue;
        }

        // get the filename e.g. [CAM1]image6-2017-12-13-21-32-24.jpg
        char file_name[50];
        strncpy(file_name, ent->d_name, 49);
        file_name[49] = '\0';

        // get the filepath e.g. images/[CAM1]image6-2017-12-13-21-32-24.jpg
        char pathname[80];
        char * filename = "images/";
        strcpy(pathname, filename);
        strcat(pathname, file_name);

        printf("FILENAME: %s\n", file_name);
        printf("PATHNAME: %s\n", pathname);

        // open file for read
        int input_file;
        input_file = open(pathname, O_RDONLY);
        if (input_file == -1) {
            printf("Couldn't read file!\n");
            exit(EXIT_FAILURE);
        }

        /*********Send filesize over socket*****/
        // get filesize
        struct stat st;
        stat(pathname, &st);
        long file_size = (long)st.st_size;
        char fileSizeString[10];
        // convert file_size to string
        const int n = snprintf(NULL, 0, "%lu", file_size);
        assert(n > 0);
        int c = snprintf(fileSizeString, n + 1, "%lu", file_size);
        assert(fileSizeString[n] == '\0');
        assert(c == n);
        printf("file size:%s\n", fileSizeString);
        int bytes_written = write(new_socket, fileSizeString, sizeof(fileSizeString));

        /*********Send filename over socket*****/
        bytes_written = write(new_socket, file_name, sizeof(file_name));

        /*********Send filedata over socket*****/
        while (1) {
            // Read data into buffer.  We may not have enough to fill up buffer, so we
            // store how many bytes were actually read in bytes_read.
            int bytes_read = read(input_file, buffer, sizeof(buffer));
            if (bytes_read == 0) // We're done reading from the file
                break;

            if (bytes_read < 0) {
                // handle errors
                printf("read error!\n");
                exit(EXIT_FAILURE);
            }

            // You need a loop for the write, because not all of the data may be written
            // in one call; write will return how many bytes were written. p keeps
            // track of where in the buffer we are, while we decrement bytes_read
            // to keep track of how many bytes are left to write.
            void* p = buffer;
            while (bytes_read > 0) {
                int bytes_written = write(new_socket, p, bytes_read);
                if (bytes_written <= 0) {
                    // handle errors
                }
                bytes_read -= bytes_written;
                p += bytes_written;
            }

        } 

    }
    closedir(dir);
    close(new_socket); //close connection with specific client
    close(server_fd); // close connection to stop listening

    return 0;
}

python客户端

# Read header size and multiple file data over tcp socket
#!/usr/bin/env python

import socket
import sys
import string

TCP_IP = '192.168.0.102'
TCP_PORT = 8080

MESSAGE = "Hello, bakalolo speaking"

#f = open('torecv.jpg','wb')

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(MESSAGE)

while(True):

    print "*************************************************"

    # ----------Read file size (10 bytes) from socket-----
    fileSizeRecievedCounter = 0 #store number of file size bytes read so far
    fileSize = "" # store file size data as string when read
    l = s.recv(10)
    # if no more data left, all images should be read from server.
    if len(l) == 0:
        break 
    fileSizeRecievedCounter += len(l) #incriment bytes read counter
    fileSize += l #concat read data to filename
    # Keep reading until we have 10 bytes just in case
    while(fileSizeRecievedCounter < 10):
        l = s.recv(10 - fileSizeRecievedCounter)
        fileSizeRecievedCounter += len(l)
        fileSize += l

    print "file sizeb4convert:", repr(l)
    l = l.split('\0', 1)[0]
    #l = filter(lambda x: x in string.printable, l) #remove byte values from string
    fileSize = int(l)
    print "file size:", repr(fileSize)

    # ----------Read file name (50 bytes) from socket-----
    fileNameRecievedCounter = 0 #store number of file name bytes read so far
    fileName = ""
    # read file name
    l = s.recv(50)
    fileNameRecievedCounter += len(l) #incriment bytes read counter
    fileName += l #concat read data to filename
    while(fileNameRecievedCounter < 50):
        l = s.recv(50 - fileNameRecievedCounter)
        fileNameRecievedCounter += len(l)
        fileName += l

    print "file nameb4convert:", repr(fileName)
    fileName = fileName.split('\0', 1)[0]
    #fileName = filter(lambda x: x in string.printable, l)
    print "file name:", repr(fileName)


    f = open(fileName,'wb')
    # read file data
    fileSizeRecieved = 0 #store number of bytes read so far
    l = s.recv(1024)
    f.write(l)
    fileSizeRecieved += len(l) #add bytes read to counter
    while (l):

        if fileSizeRecieved == fileSize:
            break

        bytesLeft = fileSize - fileSizeRecieved
        if bytesLeft < 1024: #if less than 1024 bytes left, read how much is left
            l = s.recv(bytesLeft)
            f.write(l)
            fileSizeRecieved += len(l)
        else:
            l = s.recv(1024)
            f.write(l)
            #print "Receiving...", len(l)
            fileSizeRecieved += len(l)

    print "Done receiving! Total:", fileSizeRecieved

f.close()
s.close()

#print "received data:", l