1. 程式人生 > >使用socket tcp實現簡單的檔案傳輸

使用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

接收成功後解壓這個檔案測試傳輸是否成功。