【转】网络文件传输2之C语言版的FILE

用这个,主要是为跨平台考虑.ACE现在有封装C语言的FILE功能,有些函数大同小异

以下是代码:

-----------------------服务端-----------------------

#include "stdafx.h"
#include<Winsock2.h>
#include <windows.h>
#include <stdio.h>
#include<iostream>
using namespace std;
#pragma comment(lib,"Ws2_32.lib")

int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA wsaData;
    ::WSAStartup(0x0002,&wsaData);
    SOCKET sServer=socket(AF_INET,SOCK_STREAM,0);
    SOCKADDR_IN sbind;
    sbind.sin_family=AF_INET;
    sbind.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
    sbind.sin_port=htons(12345);
    bind(sServer,(SOCKADDR*)&sbind,sizeof(SOCKADDR));
    listen(sServer,10);
    SOCKADDR_IN addr_accept;
    int len=sizeof(SOCKADDR);    
    printf("接收客户端套接字开始:\n");
    SOCKET Server;
    Server=accept(sServer,(SOCKADDR*)&addr_accept,&len);

    printf("发送文件!\n====================================\n");
    ////////////////////////发送文件部分:独立模块
    FILE *fp;
    if( (fp  = fopen( "C:\\5.JPG", "rb" )) == NULL )
    {printf( "The file 'data' was not opened\n" );return 0;}
    printf( "The file 'data' was opened\n" );
    fseek(fp,0,SEEK_END);//因为ftell定义Gets the current position of a file pointer.
    long nlenTotal=ftell(fp);     //所以将指针移到文件最后.
    char sendbuf[1024]={0};
    fseek(fp,0,SEEK_SET);

    int nlenAlready = 0;
    while(1)
    {
        if(nlenTotal==0)
        {
            printf("文件已读完,能够退出了\n");
            break;
        }
        else
        {
            fseek(fp,nlenAlready,SEEK_SET);//必须用.默认是读多少自动移多少,缺点是出错了也是继续向后移,这里就必须人工干预了
            int nfread=fread(&sendbuf,1,1024,fp);
            if(SOCKET_ERROR==send(Server,(char*)&sendbuf,nfread,0))//参数3,是指定发送的大小,在最后一次肯定小于1024字节,比如500字节,这里只从缓冲区读500字节发出去.客户端收到实际是500字节,不会造成客户端问题
            {
                printf("send错误:nSend==-1\n");//这个地方出错了,不要closesocket之类或者break/return 0之类退出,重发即可
            }
            else
            {
                nlenTotal=nlenTotal-nfread;
                nlenAlready += nfread;
            }
        }
    }
    Sleep(5000);//视文件长度停止多长时间,因为上面的发文件是一发完就退出程序,此时若接受方没收完,会报10054的错误
    if( fclose( fp ) )
        printf( "The file 'data' was not closed\n" );
    printf("已发包!\n====================================\n");
    return 0;
}

-----------------------客户端-----------------------

#include "stdafx.h"
#include<Winsock2.h>
#include <windows.h>
#include <stdio.h>
#include<iostream>
using namespace std;
#pragma comment(lib,"Ws2_32.lib")

int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA wsaData;
    ::WSAStartup(0x0002,&wsaData);
    SOCKET sClient=socket(AF_INET,SOCK_STREAM,0);
    SOCKADDR_IN addr_conect;
    addr_conect.sin_family=AF_INET;
    addr_conect.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
    addr_conect.sin_port=htons(12345);
    if(SOCKET_ERROR==connect(sClient,(SOCKADDR*)&addr_conect,sizeof(SOCKADDR)))
    {cout<<"连接服务端错误!"<<endl;closesocket(sClient);WSACleanup();return 0;}

    printf("==============================\n开始接收文件\n");
    ////////////////////////接受文件部分:独立模块
    char recvbuf[1024]={0};
    int nfwrite=0;
    DWORD nRecv=0;
    int nlen=62732;//文件长度
    int nlenRecv=0;            
    FILE *fp;
    if( (fp  = fopen( "D:\\5.JPG", "wb" )) == NULL )
    {printf( "The file 'data' was not opened\n" );return 0;}
    printf( "The file 'data' was opened\n" );
    do
    {
        nRecv=recv(sClient,recvbuf,sizeof(recvbuf),0);
        printf("recv长度=%d\n",nRecv);
        if(SOCKET_ERROR==nRecv)  
        {
            printf("recv错误:SOCKET_ERROR==nRecv,错误码=[%d]\n",WSAGetLastError());
            //注意用WSAGetLastError()获取错误码,注意10054是超时(或者理解成Connection reset by peer)
            break;
        }
        else if(nRecv==0)
        {
            printf("连接断开\n");
            break;
        }
        else
        {
            nlenRecv=nlenRecv+nRecv;
            nfwrite=fwrite(&recvbuf,1,nRecv,fp);
            if(nfwrite==0)
            {printf("file write error!\n");return 0;}
        }
    }while(nlenRecv!=nlen);
    printf("文件传输完成,接受的文件总长=%d,nlen=%d\n",nlenRecv,nlen);
    fclose(fp);
    printf("发送完文件\n==============================\n");
    closesocket(sClient);
    WSACleanup();
    return 0;
}

//备注1:文件长度
//int nlen=62732;//文件长度.按道理是发送方告诉接受方的,此处为不影响主题,所以直接把长度写进接受方,不过用的时候要注意一定要告诉对方你的文件长度
//备注2:文件路径
//发送方C:\\5.JPG,接受方D:\\5.JPG//
//备注3:图片在文章中大小是62732

 

 附注1:服务端用的是FILE,客户端用的是CFile.更新中..

posted @ 2012-05-16 21:47  完美视界  阅读(216)  评论(0)    收藏  举报