Linux C TCPSocket 传输文件简单实例-多线程实现

在Linux下使用C语言TCPSocket实现简单文件传输,包括客户端和服务器端,其中,服务器端使用多线程实现同时接收多个客户端发送的文件。

发送文件内容之前,首先需要将文件名和长度信息发送到服务器,为了便于区分,采用发送结构体的方式,设置标志位,1标识数据域为文件名,2标识数据域为文件内容,3标识发送结束,4标识发送文件长度。这样便可区分发送的内容。

服务器端代码如下:

/*多线程实现接收多个客户端的文件*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define PORT 8887
#define BUFF_SIZE 1024

typedef struct{
    char type;
    char data[BUFF_SIZE];
}m_package;

void* process_client();

int main(){
    int ss = create_tcp_server(PORT);
    if(-1 == ss)
        exit(-1);
    while(1){
        //接受客户端连接
        socklen_t addrlen = sizeof(struct sockaddr);
        struct sockaddr_in client_addr; //客户端地址结构
        int client_sock = accept(ss, (struct sockaddr*)&client_addr, &addrlen);
        if(client_sock < 0){
            printf("accept error\n");
        }
        printf("accept success\n");

        pthread_t pid;
        if(pthread_create(&pid, NULL, process_client, &client_sock) < 0){
            printf("pthread_create error\n");
        }
    }
}

//处理客户端程序
void *process_client(void *arg){
    int size = 0, fd, count = 0, sockid = *(int*)arg;
    m_package pac;
    long total = 0, cur = 0;
    //循环接收文件
    while(1) {
        memset(&pac, 0, sizeof(pac));
        size = read(sockid, &pac, sizeof(pac));
        if(size > 0){
            if (pac.type == 1){
                fd = open(pac.data, O_CREAT|O_WRONLY, 0777);
                if(-1 == fd){
                    printf("open file error!\n");
                    continue;
                }
                count = total = cur = 0;
            }
            else if (pac.type == 2){
                cur += write(fd, pac.data, strlen(pac.data));
                if(count++ % 5000 == 0){
                    printf("recv from client < %d > : %.01lf\%\n", sockid, cur * 100.0 / total);
                    count = 0;
                }
            }
            else if (pac.type == 3){
                printf("recv from client < %d > : 100.0\%\n", sockid);
                printf("recv success\n");
                close(fd);
            }
            else if(pac.type == 4){//文件长度
                total = strtol(pac.data, NULL, 10);
                printf("%ld\n", total);
            }
        }else{
            printf("client disconnected\n");
            close(sockid);
            break;
        }
    }
    return 0;
}

服务器端对创建服务器代码进行了简单封装,需要在工程下添加相关的头文件和源文件,添加的代码见博客:http://blog.csdn.net/wanna_wsl/article/details/53712066

客户端对创建连接同样进行了简单封装,需引进封装的代码,同样参见博客
http://blog.csdn.net/wanna_wsl/article/details/53712066
客户端代码如下:

#include 
#include 
#include 

#define PORT 8888
#define BUFF_SIZE 1024

typedef struct{
    char type;
    char data[BUFF_SIZE];
}m_package;

int main(){
    //创建连接
    int sock_fd = connect_tcp("192.168.134.188", PORT);
    if(-1 == sock_fd)
        return -1;

    m_package pac;
    int fd, cur = 0, count = 0;
    long filesize = 0;
    while(1){
        //打开文件
        memset(&pac, 0, sizeof(pac));
        pac.type = 1;
        // strcpy(pac.data, "/home/SKZH/a.txt");
        scanf("%s", pac.data);
        //获取文件信息
        struct stat sfile;
        stat(pac.data, &sfile );
        filesize = sfile.st_size;
        time_t t;
        long begin = time(&t);
        cur = count = 0;

        fd = open(pac.data, O_RDONLY);
        if(-1 == fd){
            printf("file open error\n");
            continue;
        }
        //读取文件并发送
        //发送文件名
        strcpy(pac.data, strrchr(pac.data, '/') + 1);
        write(sock_fd, &pac, sizeof(pac));
        memset(&pac, 0, sizeof(pac));

        //发送文件长度
        pac.type = 4;
        sprintf(pac.data,"%ld",filesize);
        write(sock_fd, &pac, sizeof(pac));
        memset(&pac, 0, sizeof(pac));

        int read_len = 0;
        while((read_len = read(fd, pac.data, BUFF_SIZE)) > 0){
            pac.type = 2;
            write(sock_fd, &pac, sizeof(pac));
            memset(&pac, 0, sizeof(pac));
            cur += read_len;
            if(count++ % 5000 == 0){
                count = 0;
                printf("send to server : %.1lf\%\n", cur * 100.0 / filesize);
            }
        }

        //发送结束标记
        memset(&pac, 3, sizeof(pac));
        write(sock_fd, &pac, BUFF_SIZE + 1);
        close(fd);

        printf("send to server : 100.0\%\n");
        printf("file size : %d B\n", filesize);
        printf("time : %ld ms\n", time(&t) - begin);
        printf("send file success\n");
        printf("------------------------\n");
    }
    close(sock_fd);
}

源码下载地址:
https://github.com/Wushaoling/Linux-C-Socket/tree/master/TCP/TCP%E6%96%87%E4%BB%B6%E4%BC%A0%E8%BE%93

你可能感兴趣的:(Linux)