TCP文件传输(服务端的文件下载)

目录

 一、TCP客户端文件上传

二、TCP传输的流程 ( 服务端 )

1. WSAStartup函数

2.socket函数

3.bind函数

4.listen函数

 5.accept函数

6.recv函数

7.send函数

8.closesocket和WSACleanup函数

 三、main函数


 一、TCP客户端文件上传

TCP文件传输( 客户端的文件上传 )icon-default.png?t=N7T8https://blog.csdn.net/2302_77573185/article/details/140999259

二、TCP传输的流程 ( 服务端 )

1. WSAStartup函数

1.WSAStartup()
        在应用程序当中调用Winsock API 函数,首先通过WSAStartup 函数完成对Winsock服务的初始化,因此需要调用WSAStartup 函数,使用Socket的程序在使用Socket之前必须调用WSAStartup函数。

2.socket函数

         套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。

int socket(int af, int type, int protocol);
  1)af 为是 IP 地址类型,常用的有 AF_INET(IPv4 地址)和 AF_INET6(IPv6 地址);

  2)type 为数据传输方式,常用的有 SOCK_STREAM(流格式套接字/面向连接的套接字)         和 SOCK_DGRAM ( 数据报套接字/无连接的套接字 );
  3)protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP         传输协议和 UDP 传输协议,设为0时系统自动匹配对应传输协议;

例如:

SOCKET sockservice = socket(AF_INET,SOCK_STREAM,0);

3.bind函数

        bind()函数将长为addlen的参数my_addr 与 sockfd 绑定在一起。

int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);

 1)sockfd 是用 socket()函数创建的文件套接字描述符;
 2)my_addr 是指向一个结构为 sockaddr 参数的指针,sockaddr 中包含了地址、端口和 IP        地址的信息。在进行地址绑定的时候,需要先将地址结构 struct sockaddr 中的 IP 地             址、端口、类型等中的域进行设置后才能进行绑定,这样进行绑定后才能将套接字文件         描述 符与地址等结合在一起; 如下:

sockaddr_in service;
    service.sin_addr.S_un.S_addr = 0;//IP地址
    service.sin_family = AF_INET;//IPV4
    service.sin_port = htons(1234);//端口号

 3)addrlen 是 my_addr 结构的长度,可以设置成 sizeof(struct sockaddr)。
       bind()函数的返回值为0时表示绑定成功,-1表示绑定失败。

例如:

bind(sockservice, (sockaddr *) &service, sizeof (service));

4.listen函数

        当一个 TCP 连接请求到达时,listen 函数会让该套接字进入监听状态,等待客户端发起连接。

int listen(int sockfd, int backlog); 

 1)sockfd 是用 socket()函数创建的文件套接字描述符;

 2)backlog 是调用 listen() 函数设置最大同时处理的连接数(backlog),即允许排队的

       最大未接受连接数。如果超过这个限制,后续的连接请求将会被暂时拒绝;

例如:

listen(socklisten, 10);

 5.accept函数

        从处于 established 状态的连接队列头部取出一个已经完成的连接,如果这个队列没有已经完成的连接,accept()函数就会阻塞,直到取出队列中已完成的用户连接为止。

int accept(int sockfd, struct sockaddr * cliaddr, socklen_t *addrlen);

 1)sockfd 是用 socket()函数创建的文件套接字描述符;

 2)  cliaddr 用来返回已连接的对端(客户端)的协议地址;

 3)  addrlen客户端地址长度;

 返回值:已连接的套接字描述符

例如:

sockaddr_in addrclient;
int nsize =sizeof(addrclient);
SOCKET sockWaiter = accept(socklisten,(struct sockaddr*)&addrclient,&nsize);

6.recv函数

        recv函数是指从TCP连接的另一端接收数据。

int send( SOCKET s, const char FAR *buf, int len, int flags );

   1)s 为指定发送端套接字

   2)buf 为一个存放应用程序要接收数据的缓冲区;

   3)len 为实际要发送的数据的字节数;

   4)flags 为执行方式,一般置0;

例如:

char szbuf[1024] = {0};
recv(sockWaiter,szbuf,sizeof(szbuf),0);

7.send函数

        send函数是指从TCP连接的另一端接收数据。

int send( SOCKET s, const char FAR *buf, int len, int flags );

   1)s 为指定发送端套接字

   2)buf 为一个存放应用程序要发送数据的缓冲区;

   3)len 为实际要发送的数据的字节数;

   4)flags 为执行方式,一般置0;

例如:

char sebuf[1024]={0};
send(sockWaiter,sebuf,sizeof(sebuf),0);

8.closesocket和WSACleanup函数

        closesocket该函数是Windows系统中的一个重要函数,它用来关闭已经打开的socket,参数是一个已经创建好的socket描述符,该函数会将socket描述符标记为无效,并将相应的描述符从系统中移除。在程序完成之后,都应该使用closesocket函数关闭socket,以保证系统资源能够及时被释放。如果不关闭socket,将出现资源泄漏的情况,影响程序的正常运行。
        WSACleanup为程序结束需要停止Socket库的使用,需要调用WSACleanup函数,这一步和最开始的WSAStartup是对应的。

 三、main函数

#include <QCoreApplication>
#include <winsock.h>
#include <iostream>
#include <windows.h>
using namespace std;
#define Onepage 4096

//若使用VS,在此需引入ws2_32网络库
//qt则在.pro文件中加入


struct FILEHEADER{
    char m_FileName[MAX_PATH];
    long m_Filesize;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    /*
     * 1.选择种类 火锅 韩餐 烤肉 --WSAStartup();
     * 2.雇店长 --socket();
     * 3.找地方 --bind();
     * 4.宣传 --listen();
     * 5.接客人进店里,交给服务员 --accept();
     * 6.服务员等着客人说话 --recv();
     * 7.回复 --send();
     * 8.下班,关店 --closesocket();WSACleanup();
   */
/********************************1***************************************/
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        /* Tell the user that we could not find a usable */
        /* Winsock DLL.                                  */
        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }

    /* Confirm that the WinSock DLL supports 2.2.*/
    /* Note that if the DLL supports versions greater    */
    /* than 2.2 in addition to 2.2, it will still return */
    /* 2.2 in wVersion since that is the version we      */
    /* requested.                                        */

    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        printf("Could not find a usable version of Winsock.dll\n");
        WSACleanup();
        return 1;
    }
    else
        printf("The Winsock 2.2 dll was found okay\n");
/********************************2***************************************/
    //2.雇店长
    SOCKET socklisten = socket(AF_INET,SOCK_STREAM,0);
    if(INVALID_SOCKET == socklisten){
        printf("sock erro\n");
    }
/********************************3***************************************/
    //3.找地方
    sockaddr_in service;
    service.sin_addr.S_un.S_addr = 0;
    service.sin_family = AF_INET;
    service.sin_port = htons(1234);

    if (bind(socklisten, (sockaddr *) &service, sizeof (service)) == SOCKET_ERROR) {
        printf("bind erro\n");
    }
/********************************4***************************************/
    //4.宣传
    if (listen(socklisten, 10) == SOCKET_ERROR){
        printf("listen erro\n");
    }
/********************************5***************************************/
    sockaddr_in addrclient;
    int nsize =sizeof(addrclient);
    SOCKET sockWaiter = accept(socklisten,(struct sockaddr*)&addrclient,&nsize);
    char szbuf[Onepage] = {0};
    char sebuf[10]={0};
    int nst = 0;
/********************************6-7**************************************/
    FILEHEADER fh;
    recv(sockWaiter,(char*)&fh,sizeof(fh),0);
    cout<<"file name: "<<fh.m_FileName<<" file size: "<<fh.m_Filesize<<endl;
    cout<<"Receive yes or no"<<endl;
    cin>>sebuf;
    send(sockWaiter,sebuf,sizeof(sebuf),0);

    if(strcmp(sebuf,"yes")== 0)
    {
        cout<<"please input save path"<<endl;
        char szPath[MAX_PATH]={0};
        cin>>szPath;
        strcat(szPath,fh.m_FileName);
        FILE*pf = fopen(szPath,"wb");
        while(1){
            int nRead=recv(sockWaiter,szbuf,sizeof(szbuf),0);
            if(nRead > 0){
                fwrite(szbuf,sizeof(char),nRead,pf);
                nst+=nRead;
            }
            cout<<"save speed: "<<nst*100/fh.m_Filesize<<"%"<<endl;
            if(nst==fh.m_Filesize)break;
        }
        fclose(pf);
        cout<<"save ok"<<endl;
    }
/********************************8***************************************/
    closesocket(socklisten);
    WSACleanup();

    return a.exec();
}

  • 23
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值