完成端口文件传输

【转自】http://blog.csdn.net/firebird321/article/details/2417168 

完成端口文件传输

分类: 网络编程   2434人阅读  评论(3)  收藏  举报
服务端

#include "StdAfx.h"
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <winsock2.h>
#include <string>
#pragma comment(lib, "Ws2_32.lib")

using namespace std;
using namespace boost; 

#define PORT 4567
#define DATA_BUFSIZE 1000
#define FileName "c://test.rar"

typedef struct tagPER_HANDLE_DATA
{
    SOCKET Socket;
    sockaddr_in addr;
}PER_HANDLE_DATA, *LPPER_HANDLE_DATA;

//单I/O操作数据
typedef struct tagPER_IO_DATA
{
    OVERLAPPED Overlapped;
    WSABUF DataBuf;
    char buffer[DATA_BUFSIZE];
    int BufferLen;
    int OperationType;   //读写标志
}PER_IO_DATA, *LPPER_IO_DATA;

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID);

int main(int argc,char * argv[])
{    
    HANDLE CompletionPort;
    WSADATA wsd;
    SYSTEM_INFO SystemInfo;
    SOCKADDR_IN InternetAddr;
    SOCKET Listen;

    int err=WSAStartup(MAKEWORD(2, 2), &wsd);
    if (err == SOCKET_ERROR)
    {
        cout << "Init Socket error..." << endl;
        return -1;
    }

    CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
    GetSystemInfo(&SystemInfo);

    for (int i = 0; i < (int)SystemInfo.dwNumberOfProcessors; ++i)
    {
        HANDLE ThreadHandle;
        ThreadHandle = CreateThread(NULL,0,ServerWorkerThread,CompletionPort,0,NULL);
        CloseHandle(ThreadHandle);
    }

    Listen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);

    InternetAddr.sin_family = PF_INET;
    InternetAddr.sin_port = htons(PORT);
    InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    err=bind(Listen, (SOCKADDR*)&InternetAddr, sizeof(InternetAddr));
    if (err<0)
    {
        cout << "Bind socket error..." << endl;
        WSACleanup();
        return -1;
    }

    listen(Listen, 200);      
    
    DWORD RecvBytes = 0;
    DWORD Flags = 0;

    while (TRUE)
    {
        PER_HANDLE_DATA * PerHandleData = NULL;
        SOCKADDR_IN saRemote;
        SOCKET Accept;
        int RemoteLen;
        RemoteLen = sizeof(saRemote);
        Accept = accept(Listen, (SOCKADDR*)&saRemote, &RemoteLen);

        PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));

        cout << "Socket number " << Accept << " connected" << endl;

        PerHandleData->Socket = Accept; //Socket
        PerHandleData->addr=saRemote;   //对方地址

        //将接收套接字和完成端口关联起来
        CreateIoCompletionPort((HANDLE)Accept,CompletionPort,(DWORD)PerHandleData,0);

        // 单I/O操作数据
        LPPER_IO_DATA PerIoData = NULL;
        PerIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
        ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
        PerIoData->DataBuf.len = DATA_BUFSIZE;
        PerIoData->DataBuf.buf = PerIoData->buffer;
        PerIoData->OperationType = 0;        //投递第一个请求
        WSARecv(PerHandleData->Socket,&(PerIoData->DataBuf),1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);
    }

    return 0;
}

DWORD WINAPI ServerWorkerThread(LPVOID lpParam)
{
    HANDLE CompletionPort = (HANDLE)lpParam;
    DWORD BytesTransferred;

    LPOVERLAPPED lpOverlapped;
    LPPER_HANDLE_DATA PerHandleData = NULL;
    LPPER_IO_DATA PerIoData = NULL;

    DWORD RecvBytes;
    DWORD Flags=0;
    BOOL bRet = FALSE;

    //文件信息
    HANDLE hFile;
    hFile = ::CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if(INVALID_HANDLE_VALUE == hFile)
    {
        cout << "需要发送的文件不存在" << endl;
        return 0;
    }
    //存放到内存中
    //取得文件大小(字节)
    DWORD dwLen = GetFileSize(hFile, NULL);    
    char *readBuf = new char[dwLen];    
    memset(readBuf, 0, dwLen);

    DWORD dwReadLen;
    //将文件内容存放到 readBuf 中。然后将 readBuf 中的内容发送给客户端 加载到内存
    ReadFile(hFile, readBuf, dwLen, &dwReadLen, NULL);            
    
    while (TRUE)
    {
        bRet = GetQueuedCompletionStatus(CompletionPort,&BytesTransferred,(PULONG_PTR)&PerHandleData,(LPOVERLAPPED*)&lpOverlapped,INFINITE);
        PerIoData = (LPPER_IO_DATA)CONTAINING_RECORD(lpOverlapped, PER_IO_DATA,Overlapped);

        if (BytesTransferred == 0)
        {
            cout << "Socket number " << PerHandleData->Socket << " closed" << endl;

            shutdown(PerHandleData->Socket,SD_BOTH);
            closesocket(PerHandleData->Socket);
            GlobalFree(PerHandleData);
            GlobalFree(PerIoData);
            continue;
        }
        
        //数据处理成功了!这儿就收到了来自客户端的数据
        //这里暂时注释,除非作为聊天程序才启用
        //cout <<"Socket: " << PerHandleData->Socket << " Says:" << PerIoData->DataBuf.buf << endl;

        if (dwLen > 0)
        {
            //发送文件长度给客户端(应该把文件名也发过去)
            if(strcmp( PerIoData->DataBuf.buf, "ready" )==0) 
            {            
                string sLen = boost::lexical_cast<string>(dwLen); 
                send(PerHandleData->Socket, sLen.c_str() ,strlen(sLen.c_str()) + 1, 0);                
            } 
            //发送第一块数据给客户端
            else if (strcmp( PerIoData->DataBuf.buf, "go" )==0)
            {
                int nBufSize = 0;
                if (dwLen > DATA_BUFSIZE)
                {
                    nBufSize = DATA_BUFSIZE;
                }
                else
                {
                    nBufSize = dwLen;
                }
                
                char *pBuf = new char[nBufSize];
                memset(pBuf, 0, nBufSize);                
                MoveMemory(pBuf, readBuf, nBufSize);

                //cout << "第一块数据内容: " << endl << pBuf << endl;
                //Sleep(10000);
                send(PerHandleData->Socket, pBuf ,nBufSize, 0);
                dwLen -= nBufSize;
                delete pBuf;
            }
            //继续发送剩余的文件
            else
            {
                int nBufSize = 0;
                if (dwLen > DATA_BUFSIZE)
                {
                    nBufSize = DATA_BUFSIZE;
                }
                else
                {
                    nBufSize = dwLen;                    
                }

                char *pBuf = new char[nBufSize];
                memset(pBuf, 0, nBufSize);        
                string sLen = PerIoData->DataBuf.buf;
                int nLen = boost::lexical_cast<int>(sLen);            
                MoveMemory(pBuf, readBuf+(nLen-1)*DATA_BUFSIZE, nBufSize);
                //cout << pBuf << endl;
                send(PerHandleData->Socket, pBuf ,nBufSize, 0);
                dwLen -= nBufSize;
                delete pBuf;
            }
        }

        //为下一个重叠调用建立单I/O操作数据
        ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
        PerIoData->DataBuf.len = DATA_BUFSIZE;
        PerIoData->DataBuf.buf = PerIoData->buffer;
        PerIoData->OperationType = 0; // read
        WSARecv(PerHandleData->Socket,&(PerIoData->DataBuf),1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);
    }
    
    delete readBuf;
    return 0;
}





客户端
#include <iostream>
#include <Winsock2.h>
#include <boost/lexical_cast.hpp>
#include <string>
#pragma comment(lib, "ws2_32.lib")  
#include "stdio.h"

using namespace std;
using namespace boost; 

#define PORT 4567
#define DATA_BUFSIZE 1000
#define FileName "d://test.rar"

void main()
{
    //初始化socket编程环境
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    wVersionRequested = MAKEWORD( 2, 2 );
    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 )
    {
        return;
    }
    if ( LOBYTE( wsaData.wVersion ) != 2 ||
        HIBYTE( wsaData.wVersion ) != 2 )
    {
        WSACleanup( );
        return;
    }

    //建立客户端socket
    SOCKET sockClient = socket( AF_INET ,SOCK_STREAM , 0 ) ;

    //服务器地址
    SOCKADDR_IN addrSrv ;
    //addrSrv.sin_addr.S_un.S_addr = inet_addr("124.130.50.137") ;
    addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1") ;
    addrSrv.sin_family = AF_INET ;
    addrSrv.sin_port = htons( 4567 ) ;

    //连接服务器
    connect( sockClient , (SOCKADDR*)&addrSrv , sizeof(SOCKADDR)) ;

    //告诉服务端准备开始接收文件
    send(sockClient, "ready", strlen("ready")+1, 0);
    
    //接收文件的长度
    char cFileLen[100] = {0};
    recv( sockClient , cFileLen , 100 , 0 ) ;
    int nLast = 0;
    int nLen = atoi(cFileLen);

    DWORD dwSize = 0;
    //开辟一个内存,接收文件内容,然后写到硬盘上
    char *pRecvBuf = new char[nLen+1];
    memset(pRecvBuf, 1, nLen+1);

    //第一次要包,是需要得到服务器发送的第二块数据,所以 iCount = 1
    int iCount = 1;
    //告诉服务端准备开始接收文件
    send(sockClient, "go", strlen("go")+1, 0);    
    
    while(1)
    {
        if (0 == nLen)
            break;

        int nBufSize = 0;
        if (nLen > DATA_BUFSIZE)
        {
            nBufSize = DATA_BUFSIZE;
        }
        else
        {
            nBufSize = nLen;            
        }

        char *recvBuf = new char[nBufSize];
        memset(recvBuf, 1, nBufSize);
        int rev = recv( sockClient , recvBuf , nBufSize, 0 ) ;
        dwSize += rev;
        MoveMemory(pRecvBuf+(iCount-1)*DATA_BUFSIZE, recvBuf, nBufSize);
        iCount++;        
        string strCount = boost::lexical_cast<string>(iCount);    
        if (nLen > DATA_BUFSIZE)
        //nLast = nLen;
            send(sockClient, strCount.c_str(), strlen(strCount.c_str())+1, 0);        
        nLen -= nBufSize;
        delete recvBuf;

    }
    DeleteFile(FileName);
    HANDLE hFile;
    hFile = ::CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if(INVALID_HANDLE_VALUE == hFile)
    {
        cout << "创建或打开文件时失败" << endl;
        closesocket( sockClient ) ;
        WSACleanup() ;
        return;
    }    

    //这里开始写文件
    DWORD dwWritenSize = 0;
    nLen = atoi(cFileLen);
    WriteFile(hFile, pRecvBuf, nLen, &dwWritenSize, NULL);        
    FlushFileBuffers(hFile);

    delete pRecvBuf;
    CloseHandle(hFile);

    system("pause");
    closesocket( sockClient ) ;
    WSACleanup() ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值