使用套接字(C#)文件传输 - 接收的文件不包含完整的数据 [英] File transfer using sockets (C#) - received file doesn't contain full data

查看:251
本文介绍了使用套接字(C#)文件传输 - 接收的文件不包含完整的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建的服务器和客户端使用套接字连接一个文件传输。
我现在面临的问题是,接收的文件,如果它的大小超过8KB,是不完整的。



如果您遇到这个问题,可以引导你我到找出什么我做错了(在服务器/客户端)



下面是这两种方法:



客户:

 #地区的文件传输使用C#.NET SOCKET  - 客户端

类FTClient
{
公共静态字符串curMsg_client =空闲;
公共静态无效SENDFILE(字符串文件名)
{

{
// IP地址[] = ip地址Dns.GetHostAddresses(localhost的);
// IPEndPoint IPEND =新IPEndPoint(ip地址[0],5656);

串IpAddressString =192.168.1.102;
IPEndPoint ipEnd_client =新IPEndPoint(IPAddress.Parse(IpAddressString),5656);
插槽clientSock_client =新的Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.IP);


字符串文件路径=;

文件名= fileName.Replace(\\,/);
而(fileName.IndexOf(/)-1个)
{
文件路径+ = fileName.Substring(0,fileName.IndexOf(/)+ 1);
文件名= fileName.Substring(fileName.IndexOf(/)+ 1);
}


字节[] = fileNameByte Encoding.UTF8.GetBytes(文件名);如果
(fileNameByte.Length> 5000 * 1024)
{
curMsg_client =文件大小超过5MB,请尝试用小的文件。
的回报;
}

curMsg_client =缓冲......;
串FULLPATH =文件路径文件名+;

字节[] = FILEDATA File.ReadAllBytes(完整路径);
字节[] = clientData新的字节[4 + fileNameByte.Length + fileData.Length];
字节[] = fileNameLen BitConverter.GetBytes(fileNameByte.Length);

fileNameLen.CopyTo(clientData,0);
fileNameByte.CopyTo(clientData,4);
fileData.CopyTo(clientData,4 + fileNameByte.Length);

curMsg_client =连接到服务器...;
clientSock_client.Connect(ipEnd_client);

curMsg_client =发送文件...;
clientSock_client.Send(clientData,0,clientData.Length,0);

curMsg_client =断开......;
clientSock_client.Close();
curMsg_client =文件[+ FULLPATH +]转。

}
赶上(异常前)
{
如果(ex.Message ==无连接可以作出,因为目标机器积极地拒绝它)
curMsg_client =文件发送失败,因为服务器没有运行。
,否则
curMsg_client =文件发送失败。 + ex.Message;
}

}
}

#endregion

服务器:

 #地区的文件传输使用C#.NET SOCKET  - 服务器

级容错服务器
{
IPEndPoint ipEnd_server;
插槽sock_server;
公众的ftServer()
{
//使IP端点接受通过端口5656
//这些值的任何IP地址将根据被改变****** *(和/或其他ImportSystem)
//这个最初的编码,但扔在sock.Bind(IPEND)到一个SocketException {每个套接字地址的一个用法(协议/网络ADDRES /端口)通常允许}
// IPEND =新IPEndPoint(IPAddress.Any,5656);
//
//我会这样设置(通过一个字符串,给出了IP)
串IpAddressString =192.168.1.102;
ipEnd_server =新IPEndPoint(IPAddress.Parse(IpAddressString),5656);
//
//创建与协议类型和传输数据类型
sock_server =新的Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.IP)新的Socket对象;与新创建的插座
sock_server.Bind(ipEnd_server)
//绑定终点;
}
公共静态字符串receivedPath = @C:\Users\Adrian.Constantin\Desktop\Simulare_Forder_Import\
公共静态字符串curMsg_server =停止!;


公共无效startserver的()
{

{
curMsg_server =启动...;

sock_server.Listen(100);

curMsg_server =运行,并等待接收文件;

插槽clientSock = sock_server.Accept();

字节[] = clientData新的字节[512000]。

INT receivedBytesLen = clientSock.Receive(clientData,SocketFlags.None);
clientSock.ReceiveBufferSize = 8192;

curMsg_server =接收数据......;

INT fileNameLen = BitConverter.ToInt32(clientData,0);
字符串文件名= Encoding.UTF8.GetString(clientData,4,fileNameLen);

的BinaryWriter BWRITE =新的BinaryWriter(File.Open(receivedPath +/+文件名,FileMode.OpenOrCreate)); ;
bWrite.Write(clientData,4 + fileNameLen,receivedBytesLen - 4 - fileNameLen);

curMsg_server =保存文件...;
bWrite.Close();

clientSock.Close();
curMsg_server =接收和归档的文件[+文件名+];停止的服务器。

}
赶上(SocketException前)
{
curMsg_server =文件Receving错误。
MessageBox.Show(的String.Format({0}错误CIDE:{1},ex.Message,ex.ErrorCode));
}
}


}

#endregion

编辑:2012年8月24日(我已经设法找出问题,并让服务器工作)
全代码服务器是:
服务器:

 #地区的文件传输使用C#.NET SOCKET  - 服务器

类的ftServer
{
IPEndPoint ipEnd_server;
插槽sock_server;
公众的ftServer()
{
串IpAddressString =192.168.1.102;
ipEnd_server =新IPEndPoint(IPAddress.Parse(IpAddressString),5656);
sock_server =新的Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.IP);
sock_server.Bind(ipEnd_server);
}
公共静态字符串receivedPath = @C:\;
公共静态字符串curMsg_server =停止!;


公共无效startserver的()
{

{
curMsg_server =启动...;

sock_server.Listen(100);

curMsg_server =运行,并等待接收文件;

插槽clientSock = sock_server.Accept();
clientSock.ReceiveBufferSize = 16384;

字节[] = clientData新的字节[1024 * 50000]。

INT receivedBytesLen = clientSock.Receive(clientData,clientData.Length,0);
curMsg_server =接收数据......;

INT fileNameLen = BitConverter.ToInt32(clientData,0);
字符串文件名= Encoding.UTF8.GetString(clientData,4,fileNameLen);

的BinaryWriter BWRITE =新的BinaryWriter(File.Open(receivedPath +文件名,FileMode.Append));
bWrite.Write(clientData,4 + fileNameLen,receivedBytesLen - 4 - fileNameLen);


,而(receivedBytesLen大于0)
{
receivedBytesLen = clientSock.Receive(clientData,clientData.Length,0);
如果(receivedBytesLen == 0)
{
bWrite.Close();
}
,否则
{
bWrite.Write(clientData,0,receivedBytesLen);
}
}


curMsg_server =保存文件...;
bWrite.Close();

clientSock.Close();
curMsg_server =接收和归档的文件[+文件名+(+(receivedBytesLen - 4 - fileNameLen)+接收的字节);服务器停止。

}
赶上(SocketException前)
{
curMsg_server =文件Receving错误。
MessageBox.Show(的String.Format({0}错误代码:{1},ex.Message,ex.ErrorCode));
}
}

}

#endregion


解决方案

您已经陷入插座使用的最经典的陷阱。这一个是老于伯克利..



你看,你没读过的文档开发插槽的想法:)



查看 http://msdn.microsoft.com/en-us/library/ ms145160.aspx 例如 - 什么是返回值



发送和接收方法并没有义务实际发送/接收所有数据已提供。这就是为什么他们都返回一个'诠释'说明有多少被发送/实际收到。这样的设计被保持,因为系统的内部缓冲器是有限的。如果提供999 GB的阵列发送,怎么你的网络卡将存储实际发送的?



您看到8KB门槛的行为,可能是因为在此之前是intenal缓冲区的大小,或者一个TCP网络数据包的最大尺寸..我不记得他们有多大分别,但它周围的东西。



要发送和poperly接收你的数据,你必须使用某种形式的循环,例如,在simplies形式:

  INT bytesToBeSent = arr.Length; 
INT bytesActuallySent = 0;
,而(bytesActuallySent< bytesToBeSent)
bytesActuallySent + = socket.Send(ARR,bytesActuallySent,bytesToSend - bytesActuallySent,....);



和recv - 类似


I created a server and a client for a file transfer using socket connection. The problem I'm facing is that the received file, if its size is over 8KB, is incomplete.

If you faced this issue, can you guide me onto finding out what I'm doing wrong (on the server /client side)?

Here are both methods:

Client:

#region FILE TRANSFER USING C#.NET SOCKET - CLIENT

class FTClient
{
    public static string curMsg_client = "Idle";
    public static void SendFile(string fileName)
    {
        try
        {
            //IPAddress[] ipAddress = Dns.GetHostAddresses("localhost");
            //IPEndPoint ipEnd = new IPEndPoint(ipAddress[0], 5656);

            string IpAddressString = "192.168.1.102";
            IPEndPoint ipEnd_client = new IPEndPoint(IPAddress.Parse(IpAddressString), 5656);
            Socket clientSock_client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);


            string filePath = "";

            fileName = fileName.Replace("\\", "/");
            while (fileName.IndexOf("/") > -1)
            {
                filePath += fileName.Substring(0, fileName.IndexOf("/") + 1);
                fileName = fileName.Substring(fileName.IndexOf("/") + 1);
            }


            byte[] fileNameByte = Encoding.UTF8.GetBytes(fileName);
            if (fileNameByte.Length > 5000 * 1024)
            {
                curMsg_client = "File size is more than 5Mb, please try with small file.";
                return;
            }

            curMsg_client = "Buffering ...";
            string fullPath = filePath + fileName;

            byte[] fileData = File.ReadAllBytes(fullPath);
            byte[] clientData = new byte[4 + fileNameByte.Length + fileData.Length];
            byte[] fileNameLen = BitConverter.GetBytes(fileNameByte.Length);

            fileNameLen.CopyTo(clientData, 0);
            fileNameByte.CopyTo(clientData, 4);
            fileData.CopyTo(clientData, 4 + fileNameByte.Length);

            curMsg_client = "Connection to server ...";
            clientSock_client.Connect(ipEnd_client);

            curMsg_client = "File sending...";
            clientSock_client.Send(clientData, 0, clientData.Length, 0);

            curMsg_client = "Disconnecting...";
            clientSock_client.Close();
            curMsg_client = "File [" + fullPath + "] transferred.";

        }
        catch (Exception ex)
        {
            if (ex.Message == "No connection could be made because the target machine actively refused it")
                curMsg_client = "File Sending fail. Because server not running.";
            else
                curMsg_client = "File Sending fail." + ex.Message;
        }

    }
}

#endregion

and Server:

#region FILE TRANSFER USING C#.NET SOCKET - SERVER

class FTServer
{
    IPEndPoint ipEnd_server;
    Socket sock_server;
    public FTServer()
    {
        //make IP end point to accept any IP address with port 5656
        //these values will be altered depending on ******* (and/or other ImportSystem)
        //this was initially coded, but threw a SocketException on sock.Bind(ipEnd) {Only one usage of each socket address (protocol/network addres/port) is normally permitted}
        //ipEnd = new IPEndPoint(IPAddress.Any, 5656);
        //
        //I'll set it like this (giving the IP through a string)
        string IpAddressString = "192.168.1.102";
        ipEnd_server = new IPEndPoint(IPAddress.Parse(IpAddressString), 5656);
        //
        //creating new socket object with protocol type and transfer data type
        sock_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
        //bind end point with newly created socket
        sock_server.Bind(ipEnd_server);
    }
    public static string receivedPath = @"C:\Users\Adrian.Constantin\Desktop\Simulare_Forder_Import\";
    public static string curMsg_server = "Stopped!";


    public void StartServer()
    {
        try
        {
            curMsg_server = "Starting...";

            sock_server.Listen(100);

            curMsg_server = "Running and waiting to receive file.";

            Socket clientSock = sock_server.Accept();

            byte[] clientData = new byte[512000];

            int receivedBytesLen = clientSock.Receive(clientData, SocketFlags.None);
            clientSock.ReceiveBufferSize = 8192;

            curMsg_server = "Receiving data...";

            int fileNameLen = BitConverter.ToInt32(clientData, 0);
            string fileName = Encoding.UTF8.GetString(clientData, 4, fileNameLen);

            BinaryWriter bWrite = new BinaryWriter(File.Open(receivedPath + "/" + fileName, FileMode.OpenOrCreate)); ;
            bWrite.Write(clientData, 4 + fileNameLen, receivedBytesLen - 4 - fileNameLen);

            curMsg_server = "Saving file...";
            bWrite.Close();

            clientSock.Close();
            curMsg_server = "Received and Archived file [" + fileName + "]; Server stopped.";

        }
        catch (SocketException ex)
        {
            curMsg_server = "File Receving error.";
            MessageBox.Show(String.Format("{0} Error cide: {1}", ex.Message, ex.ErrorCode));
        }
    }


}

#endregion

edit: 24.08.2012 (I've managed to find out the issue and to get the server to work) Full code for server is : SERVER:

#region FILE TRANSFER USING C#.NET SOCKET - SERVER

class FTServer
{
    IPEndPoint ipEnd_server;
    Socket sock_server;
    public FTServer()
    {
        string IpAddressString = "192.168.1.102";
        ipEnd_server = new IPEndPoint(IPAddress.Parse(IpAddressString), 5656);
        sock_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
        sock_server.Bind(ipEnd_server);
    }
    public static string receivedPath = @"C:\";
    public static string curMsg_server = "Stopped!";


    public void StartServer()
    {
        try
        {
            curMsg_server = "Starting...";

            sock_server.Listen(100);

            curMsg_server = "Running and waiting to receive file.";

            Socket clientSock = sock_server.Accept();
            clientSock.ReceiveBufferSize = 16384;

            byte[] clientData = new byte[1024 * 50000];

            int receivedBytesLen = clientSock.Receive(clientData, clientData.Length, 0);
            curMsg_server = "Receiving data...";

            int fileNameLen = BitConverter.ToInt32(clientData, 0);
            string fileName = Encoding.UTF8.GetString(clientData, 4, fileNameLen);

            BinaryWriter bWrite = new BinaryWriter(File.Open(receivedPath + fileName, FileMode.Append));
            bWrite.Write(clientData, 4 + fileNameLen, receivedBytesLen - 4 - fileNameLen);


            while (receivedBytesLen > 0)
            {
                receivedBytesLen = clientSock.Receive(clientData, clientData.Length, 0);
                if (receivedBytesLen == 0)
                {
                    bWrite.Close();
                }
                else
                {
                    bWrite.Write(clientData, 0, receivedBytesLen);
                                        }
            }


            curMsg_server = "Saving file...";
            bWrite.Close();

            clientSock.Close();
            curMsg_server = "Received and Archived file [" + fileName + "] (" + (receivedBytesLen - 4 - fileNameLen) + " bytes received); Server stopped.";

        }
        catch (SocketException ex)
        {
            curMsg_server = "File Receving error.";
            MessageBox.Show(String.Format("{0} Error code: {1}", ex.Message, ex.ErrorCode));
        }
    }

}

#endregion

解决方案

You have fallen into the most classic pitfall of socket usage. This one is as old as the idea of sockets developed at Berkely..

You see, you have not read the docs :)

See the http://msdn.microsoft.com/en-us/library/ms145160.aspx for example - what is the return value?

Both Send and Receive methods are not obligated to actually send/receive all the data you have provided. That's why they both return an 'int' describing how many was send/received actually. This design is held because the system's internal buffers are limited. If you provide an array of 999GB to be sent, how your network card will store that before it actually sends that?

You see the behaviour for 8KB threshold, probably because this is the size of the intenal buffer, or maybe the max size of a TCP network packet.. I don't remember how big they were, but it is something around that.

To send and receive your data poperly, you have to use some kind of loop, for example, in the simplies form:

int bytesToBeSent = arr.Length;
int bytesActuallySent = 0;
while(bytesActuallySent < bytesToBeSent)
    bytesActuallySent += socket.Send(arr, bytesActuallySent, bytesToSend - bytesActuallySent, ....);

and recv - similarly.

这篇关于使用套接字(C#)文件传输 - 接收的文件不包含完整的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆