使用socket tcp实现简单的文件传输

程序分为server、client两个部分,client从server获取文件。流程如下:

server:

1、创建socket,绑定端口10002,等待client连接;

2、链接后打开需要发送的文件,计算文件长度并发送长度,等待接收客户端响应;

3、客户端响应ok后,发送文件数据,发送缓冲定位8192;

4、发送结束后关闭链接;

client:

1、创建socket,链接server;

2、接收文件长度,并回复ok;

3、接收数据并写入文件,接收缓冲为8192;

4、接收结束后关闭链接;

参考代码如下:

file_server.c:

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>

#define BUF_SIZE  (8192)

unsigned char fileBuf[BUF_SIZE];

/*
 * send file
 */
void
file_server(const char *path)
{
    int skfd, cnfd;
    FILE *fp = NULL;
    struct sockaddr_in sockAddr, cltAddr;
    socklen_t addrLen;
    unsigned int fileSize;
    int size, netSize;
    char buf[10];

    if( !path ) {
        printf("file server: file path error!\n");
        return;
    }

    //创建tcp socket
    if((skfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        exit(1);
    } else {
        printf("socket success!\n");
    }

    //创建结构  绑定地址端口号
    memset(&sockAddr, 0, sizeof(struct sockaddr_in));
    sockAddr.sin_family = AF_INET;
    sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    sockAddr.sin_port = htons(10002);

    //bind
    if(bind(skfd, (struct sockaddr *)(&sockAddr), sizeof(struct sockaddr)) < 0) {
        perror("Bind");
        exit(1);
    } else {
        printf("bind success!\n");
    }

    //listen   监听  最大4个用户
    if(listen(skfd, 4) < 0) {
        perror("Listen");
        exit(1);
    } else {
        printf("listen success!\n");
    }

    /* 调用accept,服务器端一直阻塞,直到客户程序与其建立连接成功为止*/
    addrLen = sizeof(struct sockaddr_in);
    if((cnfd = accept(skfd, (struct sockaddr *)(&cltAddr), &addrLen)) < 0) {
        perror("Accept");
        exit(1);
    } else {
        printf("accept success!\n");
    }

    fp = fopen(path, "r");
    if( fp == NULL ) {
        perror("fopen");
        close(cnfd);
        close(skfd);
        return;
    }

    fseek(fp, 0, SEEK_END);
    fileSize = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    if(write(cnfd, (unsigned char *)&fileSize, 4) != 4) {
        perror("write");
        close(cnfd);
        close(skfd);
        exit(1);
    }

    if( read(cnfd, buf, 2) != 2) {
        perror("read");
        close(cnfd);
        close(skfd);
        exit(1);
    }

    while( ( size = fread(fileBuf, 1, BUF_SIZE, fp) ) > 0 ) {
        unsigned int size2 = 0;
        while( size2 < size ) {
            if( (netSize = write(cnfd, fileBuf + size2, size - size2) ) < 0 ) {
                perror("write");
                close(cnfd);
                close(skfd);
                exit(1);
            }
            size2 += netSize;
        }
    }

    fclose(fp);
    close(cnfd);
    close(skfd);
}

int
main(int argc, char **argv)
{
    if( argc < 2 ) {
        printf("file server: argument error!\n");
        printf("file_server /tmp/temp\n");
        return -1;
    }

    file_server(argv[1]);

    return 0;
}

file_client.c:

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>

#define BUF_SIZE (8192)

unsigned char fileBuf[BUF_SIZE];

void
file_client(const char *ip, const char *path)
{
    int skfd;
    FILE *fp = NULL;
    struct sockaddr_in sockAddr;
    unsigned int fileSize, fileSize2;
    int size, nodeSize;

    //创建tcp socket
    if((skfd=socket(AF_INET,SOCK_STREAM,0)) < 0) {
        perror("socket");
        exit(1);
    } else {
        printf("socket success!\n");
    }

    //创建结构设定待连接的服务器地址端口号
    memset(&sockAddr, 0, sizeof(struct sockaddr_in));
    sockAddr.sin_family = AF_INET;
    sockAddr.sin_addr.s_addr = inet_addr(ip);
    sockAddr.sin_port = htons(10002);

    /* 客户端调用connect主动发起连接请求 */
    if(connect(skfd, (struct sockaddr *)(&sockAddr), sizeof(struct sockaddr)) < 0) {
        perror("ConnectError:");
        exit(1);
    } else {
        printf("connnect success!\n");
    }

    size = read(skfd, (unsigned char *)&fileSize, 4);
    if( size != 4 ) {
        printf("file size error!\n");
        close(skfd);
        exit(-1);
    }
    printf("file size:%d\n", fileSize);

    if( (size = write(skfd, "OK", 2) ) < 0 ) {
        perror("write");
        close(skfd);
        exit(1);
    }

    fp = fopen(path, "w");
    if( fp == NULL ) {
        perror("fopen");
        close(skfd);
        return;
    }

    fileSize2 = 0;
    while(memset(fileBuf, 0, sizeof(fileBuf)), (size = read(skfd, fileBuf, sizeof(fileBuf))) > 0) {
        unsigned int size2 = 0;
        while( size2 < size ) {
            if( (nodeSize = fwrite(fileBuf + size2, 1, size - size2, fp) ) < 0 ) {
                perror("write");
                close(skfd);
                exit(1);
            }
            size2 += nodeSize;
        }
        fileSize2 += size;
        if(fileSize2 >= fileSize) {
            break;
        }
    }
    fclose(fp);
    close(skfd);
}

int
main(int argc, char **argv)
{
    if( argc < 3 ) {
        printf("file client: argument error!\n");
        printf("file_client 192.168.1.10 /tmp/temp\n");
        return -1;
    }

    file_client(argv[1], argv[2]);

    return 0;
}

测试结果:

首先启动server端,发送文件mysql-server-8.0.zip

$ ~/tmp/test/fileserver mysql-server-8.0.zip

再启动client端,接收此文件

$ ./fileclient 10.9.0.132 ./mysql.zip

接收成功后解压这个文件测试传输是否成功。


版权声明:本文为stone8761原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。