zoukankan      html  css  js  c++  java
  • Windows下通过socket进行字符串和文件传输

      今天在windows平台下,通过socket实现了简单的文件传输。通过实现这一功能,了解基本的windows网络编程和相关函数的使用方法。

      在windows平台上进行网络编程,首先都需要调用函数WSAStartup()进行链接库的初始化。如果没有使用该函数进行初始化,则后面会出现10093的错误(可以通过GetLastError()获得错误码)。

      进行初始化后,客户端和服务器进行不同的工作。但是不管是服务器还是客户端,都需要用到两个最基本的结构体,分别是SOCKET和sockaddr_in。其中,SOCKET结构体用于表示一个socket连接。sockaddr_in表示一个地址结构,用它来保存需要连接的主机ip地址及端口号,或者是需要监听的端口号。

      客户端基本流程图如下图:

      服务器基本流程图如下:

       这次实现的功能主要是:客户端向服务器发送一个字符串和一个文件(图片文件),服务器以接收到的字符串为文件名,并将接收到的文件保存到本地。

      客户端源代码如下:

    //file_transfer.h
    
    /**************************************************
     *Author:xiongmao
     *
     *Date:2016/2/22 17:53
     *
     *Description:用于网络间的文件传输
     *
    **************************************************/
    
    #pragma once
    #include <string>
    
    #ifndef WIN_SOCKET_
    #define WIN_SOCKET_
    #include <WinSock2.h>
    #pragma comment(lib , "ws2_32.lib")
    #endif
    
    using std::string;
    
    class FileTransfer
    {
    public:
        FileTransfer();
        ~FileTransfer();
        /*****************************************************************************
        * @name : setIpAndPort
        * 
        * @author : xiongmao
        * 
        * @create date : 2016/2/18 16:04
        * 
        * @function:设置目标ip地址和端口号
        * 
        * @inparam : 
        *    ip:目标ip地址
        *    port:目标端口号
        * @outparam : 
        * 
        * @last change : 2016/2/18 16:04
        *****************************************************************************/
        bool setIpAndPort(string ip,int port);
        /*****************************************************************************
        * @name : setFilePath
        * 
        * @author : xiongmao
        * 
        * @create date : 2016/2/18 16:06
        * 
        * @function:设置需要发送的文件的路径
        * 
        * @inparam : 
        *    path:文件路径
        * @outparam : 
        * 
        * @last change : 2016/2/18 16:06
        *****************************************************************************/
        bool setFilePath(string path);
        /*****************************************************************************
        * @name : sendFile
        * 
        * @author : xiongmao
        * 
        * @create date : 2016/2/18 16:07
        * 
        * @function:发送简单字符串信息和指定文件给目标主机
        * 
        * @inparam : 
        *    msg:需要发送给目标主机的一些简单信息
        *    filePath:需要传输的文件的路径
        * @outparam : 
        * 
        * @last change : 2016/2/21 16:41
        *****************************************************************************/
        bool sendFile(string msg,string filePath);
    private:
    
        const static int BUFFER_SIZE=1024;
    
        int m_Port;
        string m_IpAddr;
        string m_FilePath;
    
        WSADATA ws;
        SOCKET m_ServerSocket;
        sockaddr_in m_ServerAddr; 
    
    };
    //file_transfer.cpp
    
    #include "file_transfer.h"
    #include <fstream>
    #include <iostream>
    using namespace std;
    
    
    
    FileTransfer::FileTransfer()
    {
        m_Port=-1;
        /*
        if ( WSAStartup(MAKEWORD(2,2), &ws) != 0 )  
        {  
            printf("Init Windows Socket Failed,the error code is : %d 
    ", GetLastError());
            exit(-1);
        }
        */
    }
    
    FileTransfer::~FileTransfer()
    {
        WSACleanup();
    }
    
    bool FileTransfer::setIpAndPort(string ip,int port)
    {
        m_IpAddr=ip;
        m_Port=port;
        m_ServerAddr.sin_family = AF_INET;  
        m_ServerAddr.sin_addr.s_addr = inet_addr(m_IpAddr.c_str());  
        m_ServerAddr.sin_port = htons(m_Port);  
        return true;
    }
    
    
    bool FileTransfer::setFilePath(string path)
    {
        fstream testFile;
        testFile.open(path,ios::in);
        if(!testFile)
        {
            printf("file not exist!
    ");
            return false;
        }
        m_FilePath=path;
        return true;
    }
    
    bool FileTransfer::sendFile(string msg,string filePath)
    {
        m_FilePath=filePath;
        m_ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
        if ( m_ServerSocket == INVALID_SOCKET )  
        {  
            printf("Create Socket Failed::%d
    ", GetLastError());  
            return false;  
        }  
        if (connect(m_ServerSocket,(LPSOCKADDR)& m_ServerAddr,sizeof(m_ServerAddr))==SOCKET_ERROR)
        {
            printf("can not connect to server! NO: %d
    ",GetLastError());
            return false;
        }
        FILE * fp =fopen(m_FilePath.c_str(),"rb");
        if (fp ==NULL)
        {
            printf("file open error!");
            return false;
        }
        char buffer[BUFFER_SIZE];
        //发送文件名(在卡口中用来发送识别出来的车牌号)
        memset(buffer,0,BUFFER_SIZE);
        strncpy(buffer,msg.c_str(),msg.length());
        if(send(m_ServerSocket,buffer,msg.length(),0)<0)
        {
            printf("seng msg fail!(the error num is : %d )
    ",GetLastError());
            return false;
        }
        //发送文件数据
        memset(buffer,0,sizeof(buffer));
        int length = 0; 
        while ((length = fread(buffer, sizeof(char), sizeof(buffer), fp)) > 0) 
        { 
            if (send(m_ServerSocket, buffer, length, 0)== SOCKET_ERROR) 
            { 
                printf("Send File: %s Failed
    ", m_FilePath.c_str()); 
                printf("error num : %d
    ",GetLastError());
                return false;
            } 
            memset(buffer, 0, sizeof(buffer)); 
        } 
        fclose(fp); 
        closesocket(m_ServerSocket);
        return true;
    }

    客户端测试主函数

    //main.cpp
    
    /************************************************************************* 
      > File Name: Win_Server.c 
      > Author: SongLee 
     ************************************************************************/ 
    
    #include <iostream>
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
    #include "file_transfer.h"
    using namespace std;
    
    #define PORT 8087 
    #define SERVER_IP "127.0.0.1" 
    #define BUFFER_SIZE 1024 
    #define FILE_NAME_MAX_SIZE 512 
    #pragma comment(lib, "WS2_32") 
     
    int main() 
    { 
        while(1)
        {
            bool flag;
            string filename;
            printf("input file name:");
            cin>>filename;
            FileTransfer ft;
            ft.setIpAndPort(SERVER_IP,PORT);
            ft.setFilePath(filename);
            flag=ft.sendFile(filename,filename);
            if (flag)
            {
                printf("send file %s success 
    ",filename.c_str());
            } 
            else
            {
                printf("send file %d fail.The error code is : %d 
    ",GetLastError());
            }
        }
        system("pause");
        return 0; 
    } 

    服务器测试代码

    //main.cpp
    
    /************************************************************************* 
      > 服务器测试代码
      > 先从客户端接收一个字符串,作为文件的文件名,接着接收客户端发送过来的文
      > 件并保存至本地
     ************************************************************************/ 
     
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h> 
    #include <WinSock2.h> 
     
    #define PORT 8087 
    #define SERVER_IP "127.0.0.1" 
    #define BUFFER_SIZE 1024 
    #pragma comment(lib, "WS2_32") 
     
    int main() 
    { 
        // 声明并初始化一个服务端(本地)的地址结构 
        sockaddr_in server_addr; 
        server_addr.sin_family = AF_INET; 
        server_addr.sin_addr.S_un.S_addr = INADDR_ANY; 
        server_addr.sin_port = htons(PORT); 
    
        // 初始化socket dll 
        WSADATA wsaData; 
        WORD socketVersion = MAKEWORD(2, 0); 
        if(WSAStartup(socketVersion, &wsaData) != 0) 
        { 
            printf("Init socket dll error!"); 
            exit(1); 
        } 
    
        // 创建socket 
        SOCKET m_Socket = socket(AF_INET, SOCK_STREAM, 0); 
        if (SOCKET_ERROR == m_Socket) 
        { 
            printf("Create Socket Error!"); 
            exit(1); 
        } 
    
        //绑定socket和服务端(本地)地址 
        if (SOCKET_ERROR == bind(m_Socket, (LPSOCKADDR)&server_addr, sizeof(server_addr))) 
        { 
            printf("Server Bind Failed: %d", WSAGetLastError()); 
            exit(1); 
        } 
    
        //监听 
        if (SOCKET_ERROR == listen(m_Socket, 10)) 
        { 
            printf("Server Listen Failed: %d", WSAGetLastError()); 
            exit(1); 
        } 
        
        while (true)
        {
            printf("wait for file transfer...
    ");
            char file_name[BUFFER_SIZE];
            char buffer[BUFFER_SIZE];
    
            sockaddr_in client_addr; 
            int client_addr_len = sizeof(client_addr); 
            //首先接收发送过来的字符串
            SOCKET m_New_Socket = accept( m_Socket, (sockaddr *)&client_addr, &client_addr_len); 
            if (SOCKET_ERROR == m_New_Socket) 
            { 
                printf("Server Accept Failed: %d", WSAGetLastError()); 
                break; 
            } 
            memset(buffer,0,sizeof(buffer));
            memset(file_name,0,sizeof(file_name));
            if (recv(m_New_Socket,buffer,sizeof(buffer),0)<0)
            {
                printf("recv file name fail!
    ");
                continue;
            }
            strncpy(file_name,buffer,strlen(buffer));
            printf("recv file name : %s 
    ",file_name);
            FILE * fp = fopen(file_name,"wb");
            if (fp==NULL)
            {
                printf("open file error
    ");
                continue;
            }
            //获取字符串后继续获取文件数据
            memset(buffer, 0, BUFFER_SIZE); 
            int length = 0; 
            while ((length = recv(m_New_Socket, buffer, BUFFER_SIZE, 0)) > 0) 
            { 
                if (fwrite(buffer, sizeof(char), length, fp) < length) 
                { 
                    printf("File: %s Write Failed
    ", file_name); 
                    break; 
                } 
                memset(buffer, 0, BUFFER_SIZE); 
            }
            fclose(fp);
            printf("file transfer success!
    "); 
        }
        system("pause");
        return 0; 
    } 

      在进行编程的过程中,自己有以下几个问题没弄懂:

      (1)connect函数函数是怎么知道连接请求是否产生错误了?

      (2)当一次connect()连接成功后,如何主动关闭这个socket连接,直接调用closesocket函数就可以了吗?

  • 相关阅读:
    【微积分】 02
    【微积分】 01
    【线性代数】 09
    云南国庆八日游策划书
    Kubectl工具常用命令
    Linux 常用命令缩写及对应的
    kubectl工具的windows安装方法
    Intellij IDEA工具的常用快捷键
    如何理解docker镜像build中的上下文
    【转】在服务器上排除问题的头五分钟&常用命令
  • 原文地址:https://www.cnblogs.com/xiongmao-cpp/p/5208096.html
Copyright © 2011-2022 走看看