用Socket实现点对点的文件传输

System.Sockes命名空间了实现 Berkeley 套接字接口。通过这个类,我们可以实现网络计算机之间的消息传输和发送.而在我下面要讨论的这个议题里,我们将讨论的是用套节子实现文件的传输.这种方法有别于FTP协议实现的的文件传输方法,利用ftp的方法需要一个专门的服务器和客户端,无疑于我们要实现的点对点的文件传输太为复杂了一些。在这里,我们实现一个轻量级的方法来实现点对点的文件传输,这样就达到了intenet上任何两个计算机的文件共享。

在两台计算机传输文件之前,必需得先有一台计算机建立套节子连接并绑定一个固定得端口,并在这个端口侦听另外一台计算机的连接请求。

socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
socket.Blocking = true ;
IPEndPoint computernode1 = new IPEndPoint(serverIpadress, 8080);

socket.Bind(computernode1);

socket.Listen(-1);

当有其他的计算机发出连接请求的时候,被请求的计算机将对每一个连接请求分配一个线程,用于处理文件传输和其他服务。

while (true)
{
    clientsock = socket.Accept();
    if (clientsock.Connected)
    {
        Thread tc = new Thread(new ThreadStart(listenclient));
        tc.Start();
    }
}

下面的代码展示了listenclient方法是如何处理另外一台计算机发送过来的请求。首先并对发送过来的请求字符串作出判断,看看是何种请求,然后决定相应的处理方法。

void listenclient()
{
    Socket sock = clientsock;
    try
    {
        while (sock != null)
        {
            byte[] recs = new byte[32767];
            int rcount = sock.Receive(recs, recs.Length, 0);
            string message = System.Text.Encoding.ASCII.GetString(recs);
            //对message作出处理,解析处请求字符和参数存储在cmdList 中
            execmd=cmdList[0];
            sender = null;
            sender = new Byte[32767];

            string parm1 = "";
            //目录列举     
            if (execmd == "LISTING")
            {
                ListFiles(message);
                continue;
            }
            //文件传输
            if (execmd == "GETOK")
            {
                cmd = "BEGINSEND " + filepath + " " + filesize;
                sender = new Byte[1024];
                sender = Encoding.ASCII.GetBytes(cmd);
                sock.Send(sender, sender.Length, 0);
                //转到文件下载处理
                DownloadingFile(sock);
                continue;
            }
        }
    }
    catch (Exception Se)
    {
        string s = Se.Message;
        Console.WriteLine(s);
    }
}

至此,基本的工作已经完成了,下面我们看看如何处理文件传输的。

while (rdby < total && nfs.CanWrite)
{
    //从要传输的文件读取指定长度的数据
    len = fin.Read(buffed, 0, buffed.Length);
    //将读取的数据发送到对应的计算机
    nfs.Write(buffed, 0, len);
    //增加已经发送的长度
    rdby = rdby + len;
}

从上面的代码可以看出是完成文件转换成FileStream 流,然后通过NetworkStream绑定对应的套节子,最后调用他的write方法发送到对应的计算机。

我们再看看接受端是如何接受传输过来的流,并且转换成文件的:

NetworkStream nfs = new NetworkStream(sock);
try
{
    //一直循环直到指定的文件长度
    while (rby < size)
    {
        byte[] buffer = new byte[1024];
        //读取发送过来的文件流
        int i = nfs.Read(buffer, 0, buffer.Length);
        fout.Write(buffer, 0, (int)i);
        rby = rby + i;
    }
    fout.Close();
}

从上面可以看出接受与发送恰好是互为相反的过程,非常简单。

至此,单方向的文件传输就完成了,只需要在每个对等的节点上同时实现上面的发送和接受的处理代码就可以做到互相传输文件了。

Contributors: FHL