用socket编程实现一个简单的网络文件传输程序,如何把客户端和服务器端合为一体,即要求只启动一个程序就既能接收文件又能发送文件?
我手头有一个客户端和服务器端分开的程序,客户端只能收,服务器端只能发,但我不知如何把两者合并在一起?
请大家交交我,这个问题对大家来说应该比较简单吧,谢谢!

解决方案 »

  1.   

    不太明白你的意思,你收和发的是同一个东西吗,UDP和TCP都是全双工的吧,同时收发应该是没问题的。
      

  2.   

    你可不可以把你那两个程序给我看看吗?
    [email protected]
      

  3.   

    找到port和ip然后把客户端和服务器端的都改成一样的就行了,port最好是1000以上的端口,服务器和客户端一定要设为一样,你说一个只能收,另一个只能发?两那两个程序肯定有各个的发送和接收端吧?看看那两个是怎么写的,主要是发送到接收端的结构要一样,再仔细看看,两端都一样就行了
      

  4.   

    在统一台机器可以!client 和 server都起来就可以!不同的机器...
      

  5.   

    我才做了个这样软件,给我发mail,我给你 
    [email protected]
      

  6.   

    上边的也给我一份:[email protected]
      

  7.   

    你用什么协议?
    tcp的话,就在一个程序里自己连接自己就可以了。
    upd就更简单,直接发送到你的程序的接收端口,不就可以了吗?
      

  8.   

    我合并在一起了,不过有问题:
    合并后的程序为Transfer.exe,不妨称为:A和B,
    我启动了两个程序,A侦听,B连接“127.0.0.1”,连接成功
    如果先让A向B传文件,则B可以成功接受,
    但一旦让B向A传文件,则A无法成功接受,并且此后A再向B传,B也无法成功接受。
    反过来也是一样,即:
    如果先让B向A传文件,则A可以成功接受,
    但一旦让A向B传文件,则B无法成功接受,并且此后B再向A传,A也无法成功接受。我把关键代码帖出来,大家帮我看看吧:
    // TransferDlg.cpp : implementation file
    #define ReadSize 500
    #include "MySocket.h"
    extern CMySocket serversocket;
    extern CMySocket clientsocket;void CTransferDlg::OnSend() 
    {
    // TODO: Add your control notification handler code here
    CFile file;
    char data[ReadSize]; // 用于存放读入的文件数据块
    long ByteSended=0, FileLength,count;
    CFileDialog fd(TRUE);
    CString filename;
    char fn[40];

    if(IDOK==fd.DoModal())  // 启动用于选择文件的对话框
    {
      //选择了文件
      filename=fd.GetFileName();  //获取选择的文件的文件名
               if(!file.Open(
                      filename.GetBuffer(0),CFile::modeRead|CFile::typeBinary))
    {
    AfxMessageBox("打开文件错误,取消发送!");
    return;
    }
    strcpy(fn,filename.GetBuffer(0));
    }
    else return; //按了取消按钮

    FileLength=file.GetLength();
    clientsocket.Send(&FileLength,sizeof(long));
    clientsocket.Send(fn,40);
    memset(data,0,sizeof(data));
    do{
       // 从文件读取数据,每次最多读入ReadSize个字节。
                //count表示实际读入的字节数
      ount=file.ReadHuge(data, ReadSize);
      // 发送数据
      while(SOCKET_ERROR == clientsocket.Send(data,count))
      {
      }
      // 统计已发送的字节数
      ByteSended = ByteSended + count;
    }while(ByteSended < FileLength);
       file.Close();}void CTransferDlg::OnListen() 
    {
    // TODO: Add your control notification handler code here
    serversocket.Create(7000);
    serversocket.Listen();    
    }void CTransferDlg::OnReceive() 
    {
    // TODO: Add your control notification handler code here
        CFile file;
        char data[ReadSize];
        long FileLength;
        long WriteOnce;
        long WriteCount = 0;
        char fn[40];    // 接收文件长度
        while(SOCKET_ERROR == clientsocket.Receive(&FileLength,sizeof(long)))
    {
    }
        // 接收文件名
        while(SOCKET_ERROR == clientsocket.Receive(fn,40))  
    {
    }
            if(!file.Open(fn,CFile::modeCreate|CFile::modeWrite))
    {
         AfxMessageBox("Create file error!");
         return;
    }
        do{
         WriteOnce = clientsocket.Receive(data,ReadSize);
         if(WriteOnce == SOCKET_ERROR)
         continue;
         // 统计已接受的字节数
         WriteCount=WriteCount+WriteOnce;
         // 把收到的数据写入文件
         file.WriteHuge(data,WriteOnce);
    }while(WriteCount< FileLength);
        file.Close();
        AfxMessageBox("接收文件成功");

    }void CTransferDlg::OnConnect() 
    {
    // TODO: Add your control notification handler code here clientsocket.Create();
    clientsocket.Connect("127.0.0.1",7000);

    }
    // MySocket.cpp : implementation file
    CMySocket serversocket;
    CMySocket clientsocket;
    void CMySocket::OnAccept(int nErrorCode) 
    {
        // TODO: Add your specialized code here and/or call the base class

    if(!serversocket.Accept(clientsocket))
    {
    AfxMessageBox("连接失败");
    return;
    }
    AfxMessageBox("连接成功");
    CAsyncSocket::OnAccept(nErrorCode);}
    其中CMySocket
    class CMySocket : public CAsyncSocket不知道为什么会这样,大家帮我看看,给我指点一下吧,谢谢!
      

  9.   

    程序没有报错,我试了,
    如果先让A向B传文件,则B可以成功接受;
    但一旦让B向A传文件,则A无法成功接受,但是在这里,
    我用AfxMessageBox(fn);来看看是否接收到了文件名,奇怪的是,文件名竟然都接收到了,
    并且了最后的“接收文件成功"都显示出来了,可就是在文件夹里看不到接收的文件,很奇怪,我都晕死了。
      

  10.   

    看来你需要一个网络通讯协议,我给你定义一个看下面:
    head(1)    findex(2)    dindex(2)    flag(1)   date(1024-1-2-2-1-1) end(1)
    INF         n             0           1        (文件名字)            OVE
    BEG         n             0           0        NULL                  OVE
    DAT         n            0+x          1        (文件片段)            OVE
    NEX         n            0+x          0        NULL                  OVE
    END         n             0           1        (文件长度)            OVE
    通讯应答模式:
    发起端                                     接收端
    通知------INF------------------->准备接收文件(创建文件)注意记录findex
    <=============BEG===============准备完成
    生成第一个包-------DAT--------->根据findex找到文件,保存(文件片段)
    <============NEX===============保存完毕要求发送第二个包dindex为接收的序号
    生成第二个包-------DAT--------->根据findex找到文件,保存(文件片段)
    <===========NEX================保存完毕要求发送第三个包dindex为接收的序号
    当文件发送完毕以后----END------>查看接受文件长度如果相等表示文件接收成功
    一定要注意findex(表示文件序号),和dindex(表示文件片段序号)
    INF、BEG、DAT等的定义如:#define INF 0x01
    注意一个包可以是1024个字节,也可以更大或着更小,看你的文件而定
    int CMyMsg::MakePackage(BYTE head,int findex, int dindex, char flag, char *data)
    {
    char temp[1024];
    int len=0;
    temp[0]=head;//添加头
    memcpy(&temp[1],&findex,2);//序号
    memcpy(&temp[3],&dindex,2);
    temp[5]=flag;//数据有效位
    if (datain==1)//表示数据data有效
    {
    len=_mbstrlen(data);//获得数据长度
    memcpy(&temp[6],data,len);//拷贝数据
    }
    temp[len+6]=(BYTE)OVE;//添加尾
    memset(data,'\0',1024);//清空指针
    memcpy(data,temp,len+6);//返回帧return len+6;
    }(打包函数)读取文件的时候注意包的总长度,如果是1024读取的文件长度为1024-6
      

  11.   

    Of course.
    www.vckbase.com/code
      

  12.   

    我太菜,总算把你定义的这个格式看懂了,可是我不知道该怎么用啊?
    我打成包CMyMsg之后该怎么传啊?还是用clientsocket.Send,clientsocket.Receive传吧,
    怎么就知道用了这个就不会碰到我原来的哪些问题呢?
      

  13.   

    int CMyMsg::MakePackage(BYTE flag,int Link, int index, char datain, char *data)
    {
    char temp[1024];
    int len=0;
    MYNUM num;
    temp[0]=flag;//添加头
    num.num=Link;
    memcpy(&temp[1],num.ch,4);
    num.num=index;
    memcpy(&temp[5],num.ch,4);//序号

    temp[9]=datain;//数据有效位
    if (datain==1)//表示数据data有效
    {
    len=_mbstrlen(data);//获得数据长度
    memcpy(&temp[10],data,len);//拷贝数据
    }
    temp[len+10]=(BYTE)OVE;//添加尾
    memset(data,'\0',1024);//清空指针
    memcpy(data,temp,len+10);//返回帧return len+10;
    }这个是我修改以后的打包函数,原来的有点问题,MYNUM 是一个共用体定义为
    union MYNUM{
    char ch[4];
    int  num;
    };
    这个函数的data参数传进来的是你需要传送的文件片段,打包完成以后整个包的数据就在data中你传送的时候只要Send(data,len)len是函数返回的长度
    你解包的时候用一个switch语句.你是在OnReceive中Receive的吧!如果你把接收的数据保存在char buf[1024]中那么你的switch应该是这样
    switch(buf[0])
    {
    case INF:
    break;
    case BEG:
    break;
    ......
    }在case语句中完成我给你的协议中的工作就可以了
    说到这里了,如果还不行!!!!我一头装在墙上了
      

  14.   

    如果你按照我给你协议走,那么每个数据包都是有判断标记的。你可以从数据包中得知你当前传送的是哪个文件(findex),是文件的哪个部分(dindex)。有了这两个东西足够你找到文件,并且在文件中定位。这样可以接收方盲目接收数据!
      

  15.   

    你需要注意的是你怎么读取文件和保存文件,我修改后的打包函数每次可以传送1024-10个字节的文件,也就是你每次只能读1014个字节的文件,然后用哪个函数打包发送,在应答模式中提到的生成第一个包,意思就是让你读取文件并且用哪个函数打包。你必须注意处理findex,以及dindex。如果这两个参数错了,你的通讯就会失败!
    这个协议完全可以解决你的问题!我现在用的协议也跟这个差不多,只不过比这个麻烦一点!因为我要支持30个客户端的通讯,包括文件传送,和一般消息传送!!
      

  16.   

    sct() ,我也需要这个文件传输的程序,客户端与服务端分开的那个就可以,能给我发一份吗?先行谢过了。我的email地址:[email protected]