Socket网络程序设计(4) ———— 实现linux和windows的文件传输

用TCP/TP进行网际互连(4)

———— 实现linux和windows的文件传输

1、实现要求

· 在循环面向连接的程序基础上,利用tcp完成linux和windows平台的文件传输
· 对服务器程序进行合理的封装优化

2、分析

  • Linux服务器:
    1)首先,创建套接字,并将其绑定到提供服务的端口上,设置为被动模式,将这几步进行封装,定义int passiveTCP (const char*service)函数,传入端口号。
    2)然后,进入循环,从该套接字上接收下一个连接请求,获得该连接的新的套接字,并向其发送之前选中的文件,同时统计发送文件长度显示出来。当此客户完成交互时,关闭连接。循环接收与发送。
    3)最后,当循环结束后,关闭服务器最开始创建的用于接收客户端的套接字。
  • Windows客户端:
    1)首先,利用Windows平台下的winsock进行socket的初始化,创建并进行connect,连接服务器,此过程封装进connectTCP(IP,PORT)函数中,返回创建的socket的描述符。
    2)然后,实现文件的接收工作。(这部分代码和原来linux实现的没有太大差别)
    3)最后,关闭socket连接。

3、实现代码

  • Linux服务器:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 6000
#define LISTENQ 20
#define BUFFSIZE 4096
#define FILE_NAME_MAX_SIZE 512

int passiveTCP (const char*service){
    //Create socket
    int sockfd,connfd;
    struct sockaddr_in svraddr,clientaddr;
    bzero(&svraddr,sizeof(svraddr));

    svraddr.sin_family=AF_INET;
    svraddr.sin_addr.s_addr=htonl(INADDR_ANY);
    svraddr.sin_port=htons(PORT);

    sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(sockfd<0)
    {
        perror("socket");
        exit(1);
    }

    //bind  
    if(bind(sockfd,(struct sockaddr*)&svraddr,sizeof(svraddr))<0)
    {
        perror("bind");
        exit(1);
    }

    //listen
    if(listen(sockfd,LISTENQ)<0)
    {
        perror("listen");
        exit(1);
    }
    return sockfd;
}


int main(int argc, char **argv[])
{
    //Input the file name
    char filename[FILE_NAME_MAX_SIZE];
    bzero(filename,FILE_NAME_MAX_SIZE);
    printf("Please input the file name you wana to send:");
    scanf("%s",&filename);
    getchar();
    int sockfd,connfd;
    struct sockaddr_in clientaddr;

    sockfd = passiveTCP(PORT);


    while(1)
    {
        socklen_t length=sizeof(clientaddr);

        //accept
        connfd=accept(sockfd,(struct sockaddr*)&clientaddr,&length);
        if(connfd<0)
        {
            perror("connect");
            exit(1);
        }

        //send file imformation
        char buff[BUFFSIZE];
        int count;
        bzero(buff,BUFFSIZE);
        strncpy(buff,filename,strlen(filename)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(filename));
        count=send(connfd,buff,BUFFSIZE,0);
        if(count<0)
        {
            perror("Send file information");
            exit(1);
        }

        //read file 
        FILE *fd=fopen(filename,"rb");
        if(fd==NULL)
        {
            printf("File :%s not found!\n",filename);
        }
        else 
        {
            bzero(buff,BUFFSIZE);
            int file_block_length=0;
            while((file_block_length=fread(buff,sizeof(char),BUFFSIZE,fd))>0)
            {
                printf("file_block_length:%d\n",file_block_length);
                if(send(connfd,buff,file_block_length,0)<0)
                {
                    perror("Send");
                    exit(1);
                }
                bzero(buff,BUFFSIZE);   
            }
            fclose(fd);
            printf("Transfer file finished !\n");
        }
        close(connfd);
    }
    close(sockfd);
    return 0;
}
  • Windows客户端
#include <stdlib.h>
#include <winsock2.h>
#include <stdio.h>
//#pragma comment(lib,"ws2_32.lib") //把ws2_32.lib加到Link页的连接库
//#define IP "172.18.68.243"            //在两台计算机上测试,IP为Server端的IP地址
#define IP "192.168.248.131"                //在一台计算机上测试,IP为本地回送地址
#define PORT 6000                   //注意:客户端设置通信的端口 = 服务端的端口
#define BUFFER_SIZE 1024            //数据发送缓冲区大小

#define LISTENQ 20
#define BUFFSIZE 4096
#define FILE_NAME_MAX_SIZE 512


void recvTCP(int clientfd){
    //recv file imformation
    char buff[BUFFSIZE];
    char filename[FILE_NAME_MAX_SIZE];
    int count;
    //bzero(buff,BUFFSIZE);
    memset(buff,0,BUFFSIZE);

    count=recv(clientfd,buff,BUFFSIZE,0);
    if(count<0)
    {
        perror("recv");
        exit(1);
    }
    strncpy(filename,buff,strlen(buff)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buff));

    printf("Preparing recv file : %s  \n",filename);


    //recv file
    FILE *fd=fopen(filename,"wb+");
    if(NULL==fd)
    {
        perror("open");
        exit(1);
    }
    //bzero(buff,BUFFSIZE);
    memset(buff,0,BUFFSIZE);

    int length=0;
    while(length=recv(clientfd,buff,BUFFSIZE,0))
    {
        if(length<0)
        {
            perror("recv");
            exit(1);
        }
        int writelen=fwrite(buff,sizeof(char),length,fd);
        if(writelen<length)
        {
            perror("write");
            exit(1);
        }
        //bzero(buff,BUFFSIZE);
        memset(buff,0,BUFFSIZE);
    }
    printf("Receieved file:%s  finished!\n",filename);
    fclose(fd);
}


int connectTCP(const char *host, const char *port){
       WSADATA WSAData;
        if(WSAStartup(MAKEWORD(2,0),&WSAData)==SOCKET_ERROR)  //WSAStartup()函数对Winsock DLL进行初始化
        {
            printf("Socket initialize fail!\n");
            //continue;
        }
        SOCKET sock;                                            //客户端进程创建套接字
        if((sock=socket(AF_INET,SOCK_STREAM,0))==SOCKET_ERROR)  //创建流套接字(与服务端保持一致)
        {
            printf("Socket create fail!\n");
            WSACleanup();
            //continue;
        }

        struct sockaddr_in ClientAddr;              //sockaddr_in结构用来标识TCP/IP协议下的地址,可强制转换为sockaddr结构
        ClientAddr.sin_family=AF_INET;              //指Internet域
        ClientAddr.sin_port=htons(PORT);            //指定服务端所预留的端口
        ClientAddr.sin_addr.s_addr=inet_addr(IP);   //指定服务端所绑定的IP地址
        if(connect(sock,(LPSOCKADDR)&ClientAddr,sizeof(ClientAddr))==SOCKET_ERROR)  //调用connect()函数,向服务器进程发出连接请求
        {
            printf("Connect fail!\n");
            closesocket(sock);
            WSACleanup();
            //continue;
        }
        return sock;
}


int main()
{
    SOCKET sock;                                            //客户端进程创建套接字
    char buf[BUFFER_SIZE];                              //buf数组存放客户端发送的消息
    int inputLen;                                       //用于输入字符自增变量
    while(1)
    {
        printf("Socket\\Client>");
        inputLen=0;
        memset(buf,0,sizeof(buf));
        while((buf[inputLen++]=getchar())!='\n')        //输入以回车键为结束标识
        {
            ;
        }
        if(buf[0]=='e' && buf[1]=='x' && buf[2]=='i' && buf[3]=='t')
        {
            printf("The End.\n");
            break;
        }

        sock=connectTCP(IP,PORT);

        //send(sock,buf,BUFFER_SIZE,0);              //向服务器发送数据

        recvTCP(sock);



        closesocket(sock);                           //关闭套接字
        WSACleanup();                               //终止对Winsock DLL的使用,并释放资源,以备下一次使用
    }
    return 0;
}

4、运行效果

  • Linux服务器端:
    这里写图片描述
    发送了qwk.txt文件,长度为25。

  • Windows客户端:(codeblocks编译运行):
    这里写图片描述
    可以看到,成功接收到文件。

附上我的实验代码,测试成功的:
https://github.com/KevinBetterQ/Network-programming/tree/master/Windows-Linux


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