c# socket 傳輸文件

 int port = 1234;網絡

int port = 1234;
IPAddress ip = IPAddress.Parse("127.0.0.1");
socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
IPEndPoint iep = new IPEndPoint(ip,port);
//socket.Blocking = false;
socket.Bind(iep);
socket.Listen(10);
Console.WriteLine("start......");
try
{
for (int i = 0; i < 10;i++ )
{

}
}
catch
{
Console.WriteLine("異常!");
socket.Close();
}多線程

接收端
private void Receive(Socket socket)
{
NetworkStream ns = new NetworkStream(socket);
FileStream fs = new FileStream("c:\\file.txt", FileMode.OpenOrCreate);
bool isRead = true;
while (isRead)
{
int count = ns.Read(this._receiveBuf, 0, this._receiveBuf.Length);
int datanum = 0;
datanum = BitConverter.ToInt32(this._receiveBuf, 0); //從buffer中的前4個字節讀出count
if (datanum > 0) //肯定每次要接受多少字節數
{
fs.Write(this._receiveBuf, 4, datanum);
}
else //若是接受字節數爲0 就推出
{
isRead = false;
}
}
this.txtFile.Text = "文件傳輸成功";
fs.Close();
}
---------------------
發送端
private void btSend_Click(object sender, System.EventArgs e)
{
if (this._isConnect)
{
_ns = _tc.GetStream();
string path = this.txtPath.Text.Trim();
FileStream fs = new FileStream(path, FileMode.Open);
int sendCount = 0;
byte[] countbuffer = null;
byte[] clientbuffer = new byte[1004];
while (sendCount < fs.Length && _ns.CanWrite)
{
int count = fs.Read(_sendBuf, 0, _sendBuf.Length); //讀出要發送的數據
countbuffer = BitConverter.GetBytes(count);
countbuffer.CopyTo(clientbuffer,0);
_sendBuf.CopyTo(clientbuffer, 4);
this._ns.Write(clientbuffer, 0, 4 + count); //寫入網絡流
sendCount += count;
}
countbuffer = BitConverter.GetBytes(0); //發送完文件後 發送count = 0
this._ns.Write(countbuffer, 0, countbuffer.Length); //使接收端中止
_ns.Close();
fs.Close();
}
}異步

你爲何不把這兩種方案結合在一塊兒呢?
首先把文件的總長度和每次發送的大小先發送出去,等接收端接受並分析,而後開始。
好比每次發送4K(這是操做系統文件管理中使用到的最小文件大小,你能夠看看你係統中的任何一個文件,佔用空間都是4K的整數倍),
最後一次可能會少與4K,可是接受方是能夠計算出來的。
必要時,你可使用多線程,分段發送,接收端收集後分段組合,這還要多使用一個段號碼。
socket是最底層的類,傳輸效率最高!
對於你說的異步操做,一句話說不清楚,基本上能夠用「非阻塞模型」來歸納,就是調用後立馬返回,不是等到操做完成後才返回!
打個比方:阻塞模型
while(isok)
{
readdata(data);//從文件讀數據
send(data); //一直等到data發送完畢後才返回,其實這期間原本能夠進行下一次讀操做
//影響了效率。
if(讀完)
isok=false;
else
isok=true;
}
非阻塞模型,能夠在發送過程當中進行讀取操做,提升了效率。
固然,在第二次發送前,必須等待第一次發送操做完成才行,須要檢測和控制!socket

while (sendCount < fs.Length && _ns.CanWrite)
{
int count = fs.Read(_sendBuf, 0, _sendBuf.Length); //讀出要發送的數據
countbuffer = BitConverter.GetBytes(count);
countbuffer.CopyTo(clientbuffer,0);
_sendBuf.CopyTo(clientbuffer, 4);
this._ns.Write(clientbuffer, 0, 4 + count); //寫入網絡流
sendCount += count;
}

有點亂:你每次讀取1000仍是1004??不是前四個字節是長度嗎?爲何從文件裏讀取1004個字節啊?

 

BeginReceiveFrom 方法啓動從遠程主機異步讀取無鏈接數據報的操做。調用 BeginReceiveFrom 方法將使您可以在單獨的執行線程中接收數據。

您能夠建立一個實現 AsyncCallback 委託的回調方法並將它的名稱傳遞給 BeginReceiveFrom 方法。爲此,您的 state 參數至少必須包含用於通訊的已鏈接或默認 Socket。若是您的回調須要更多信息,則能夠建立一個小型類來保存 Socket 和其餘必需的信息。經過 state 參數將此類的一個實例傳遞給 BeginReceiveFrom 方法。

回調方法應調用 EndReceiveFrom 方法。當應用程序調用 BeginReceiveFrom 時,系統將會使用單獨的線程來執行指定的回調方法,並將在 EndReceiveFrom 上一直阻止到 Socket 讀取數據或引起異常爲止。若是想要在調用 BeginReceiveFrom 方法後使原始線程阻止,請使用 WaitHandle.WaitOne。當須要原始線程繼續執行時,請在回調方法中調用 T:System.Threading.ManualResetEvent 的 Set 方法。有關如何編寫 callback 方法的其餘信息,請參見 Callback 示例。

注意
在調用 BeginReceiveFrom 以前,必須使用 Bind 方法顯式地將 Socket 綁定到本地終結點,不然 BeginReceiveFrom 將會引起 SocketException。


該方法將數據讀入 buffer 參數中,並捕獲從其發送數據的遠程主機終結點。有關如何檢索此終結點的信息,請參考 EndReceiveFrom。若是打算從未知主機或多個主機異步接收無鏈接的數據報,則最適合使用此方法。在這些狀況下, BeginReceiveFrom 將會讀取本地網絡緩衝區接收到的第一個排隊數據報。若是您接收到的數據報大於 buffer 的大小,則 BeginReceiveFrom 方法將在 buffer 中儘量多地填充消息內容,並引起 SocketException。若是您使用的是不可靠協議,多餘的數據將會丟失。而若是當前使用的是可靠協議,則服務提供程序將保留多餘的數據,並且通 過使用一個足夠大的緩衝區調用 BeginReceiveFrom 方法來檢索這些數據。

雖然 BeginReceiveFrom 是用於無鏈接協議的,但您一樣可使用面向鏈接的協議。若是選擇這樣作,則必須經過調用 Connect / BeginConnect 方法來創建遠程主機鏈接,或者調用 Accept 或 BeginAccept 方法來接受傳入的鏈接請求。若是在創建鏈接或接受鏈接以前就調用了 BeginReceiveFrom 方法,則您將獲得 SocketException。您也能夠在調用 BeginReceiveFrom 方法以前,爲無鏈接協議創建默認遠程主機。在上述任何一種狀況下,BeginReceiveFrom 方法都會忽略 remoteEP 參數,而且只從已鏈接的或默認的遠程主機接收數據。

對於面向鏈接的套接字,BeginReceiveFrom 將讀取全部可用的數據,直到達到 size 參數所指定的字節數。

若要取消掛起的 BeginReceiveFrom,請調用 Close 方法。

下面的代碼示例異步接收來自遠程主機的無鏈接數據報。

 

BeginReceiveFrom 方法啓動從遠程主機異步讀取無鏈接數據報的操做。調用 BeginReceiveFrom 方法將使您可以在單獨的執行線程中接收數據。

您能夠建立一個實現 AsyncCallback 委託的回調方法並將它的名稱傳遞給 BeginReceiveFrom 方法。爲此,您的 state 參數至少必須包含用於通訊的已鏈接或默認 Socket。若是您的回調須要更多信息,則能夠建立一個小型類來保存 Socket 和其餘必需的信息。經過 state 參數將此類的一個實例傳遞給 BeginReceiveFrom 方法。

回調方法應調用 EndReceiveFrom 方法。當應用程序調用 BeginReceiveFrom 時,系統將會使用單獨的線程來執行指定的回調方法,並將在 EndReceiveFrom 上一直阻止到 Socket 讀取數據或引起異常爲止。若是想要在調用 BeginReceiveFrom 方法後使原始線程阻止,請使用 WaitHandle.WaitOne。當須要原始線程繼續執行時,請在回調方法中調用 T:System.Threading.ManualResetEvent 的 Set 方法。有關如何編寫 callback 方法的其餘信息,請參見 Callback 示例。

注意
在調用 BeginReceiveFrom 以前,必須使用 Bind 方法顯式地將 Socket 綁定到本地終結點,不然 BeginReceiveFrom 將會引起 SocketException。


該方法將數據讀入 buffer 參數中,並捕獲從其發送數據的遠程主機終結點。有關如何檢索此終結點的信息,請參考 EndReceiveFrom。若是打算從未知主機或多個主機異步接收無鏈接的數據報,則最適合使用此方法。在這些狀況下, BeginReceiveFrom 將會讀取本地網絡緩衝區接收到的第一個排隊數據報。若是您接收到的數據報大於 buffer 的大小,則 BeginReceiveFrom 方法將在 buffer 中儘量多地填充消息內容,並引起 SocketException。若是您使用的是不可靠協議,多餘的數據將會丟失。而若是當前使用的是可靠協議,則服務提供程序將保留多餘的數據,並且通 過使用一個足夠大的緩衝區調用 BeginReceiveFrom 方法來檢索這些數據。

雖然 BeginReceiveFrom 是用於無鏈接協議的,但您一樣可使用面向鏈接的協議。若是選擇這樣作,則必須經過調用 Connect / BeginConnect 方法來創建遠程主機鏈接,或者調用 Accept 或 BeginAccept 方法來接受傳入的鏈接請求。若是在創建鏈接或接受鏈接以前就調用了 BeginReceiveFrom 方法,則您將獲得 SocketException。您也能夠在調用 BeginReceiveFrom 方法以前,爲無鏈接協議創建默認遠程主機。在上述任何一種狀況下,BeginReceiveFrom 方法都會忽略 remoteEP 參數,而且只從已鏈接的或默認的遠程主機接收數據。

對於面向鏈接的套接字,BeginReceiveFrom 將讀取全部可用的數據,直到達到 size 參數所指定的字節數。

若要取消掛起的 BeginReceiveFrom,請調用 Close 方法。

下面的代碼示例異步接收來自遠程主機的無鏈接數據報。

C# code
IPHostEntry lipa = Dns.Resolve("host.contoso.com");
IPEndPoint lep = new IPEndPoint(lipa.AddressList[0], 11000);

Socket s = new Socket(lep.Address.AddressFamily,
SocketType.Dgram,
ProtocolType.Udp);

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint tempRemoteEP = (EndPoint)sender;
s.Connect(sender);

try{
while(true){
allDone.Reset();
StateObject so2 = new StateObject();
so2.workSocket = s;
Console.WriteLine("Attempting to Receive data from host.contoso.com");

s.BeginReceiveFrom(so2.buffer, 0, StateObject.BUFFER_SIZE,0, ref tempRemoteEP,
new AsyncCallback(Async_Send_Receive.ReceiveFrom_Callback), so2);
allDone.WaitOne();
}
}
catch (Exception e){
Console.WriteLine(e.ToString());
}ide

在端口 11000 上創建 UdpClient 鏈接。將很短的字符串消息發送到兩個單獨的遠程主機。Receive 方法在接收消息前阻止執行。使用傳遞給 Receive 的 IPEndPoint 能夠顯示響應主機的標識。

C# code
// This constructor arbitrarily assigns the local port number.
UdpClient udpClient = new UdpClient(11000);
try{
udpClient.Connect("www.contoso.com", 11000);

// Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes("Is anybody there?");

udpClient.Send(sendBytes, sendBytes.Length);

// Sends a message to a different host using optional hostname and port parameters.
UdpClient udpClientB = new UdpClient();
udpClientB.Send(sendBytes, sendBytes.Length, "AlternateHostMachineName", 11000);

//IPEndPoint object will allow us to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);

// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);

// Uses the IPEndPoint object to determine which of these two hosts responded.
Console.WriteLine("This is the message you received " +
returnData.ToString());
Console.WriteLine("This message was sent from " +
RemoteIpEndPoint.Address.ToString() +
" on their port number " +
RemoteIpEndPoint.Port.ToString());

udpClient.Close();
udpClientB.Close();

}
catch (Exception e ) {
Console.WriteLine(e.ToString());
}函數

另外若是你想保證傳輸的質量的話,用TCP/IP協議吧,它的優勢是能夠控制傳輸中的質量(下降出錯率),缺點是效率稍微低點。 TcpClient 類提供了一些簡單的方法,用於在同步阻止模式下經過網絡來鏈接、發送和接收流數據。 爲使 TcpClient 鏈接並交換數據,使用 TCP ProtocolType 建立的 TcpListener 或 Socket 必須偵聽是否有傳入的鏈接請求。可使用下面兩種方法之一鏈接到該偵聽器: 建立一個 TcpClient,並調用三個可用的 Connect 方法之一。 使用遠程主機的主機名和端口號建立 TcpClient。此構造函數將自動嘗試一個鏈接。 注意 若是要在同步阻止模式下發送無鏈接數據報,請使用 UdpClient 類。 給繼承者的說明 要發送和接收數據,請使用 GetStream 方法來獲取一個 NetworkStream。調用 NetworkStream 的 Write 和 Read 方法與遠程主機之間發送和接收數據。使用 Close 方法釋放與 TcpClient 關聯的全部資源。 下面的代碼示例創建 TcpClient 鏈接。 C# code static void Connect(String server, String message) { try { // Create a TcpClient. // Note, for this client to work you need to have a TcpServer // connected to the same address as specified by the server, port // combination. Int32 port = 13000; TcpClient client = new TcpClient(server, port); // Translate the passed message into ASCII and store it as a Byte array. Byte[] data = System.Text.Encoding.ASCII.GetBytes(message); // Get a client stream for reading and writing. // Stream stream = client.GetStream(); NetworkStream stream = client.GetStream(); // Send the message to the connected TcpServer. stream.Write(data, 0, data.Length); Console.WriteLine("Sent: {0}", message); // Receive the TcpServer.response. // Buffer to store the response bytes. data = new Byte[256]; // String to store the response ASCII representation. String responseData = String.Empty; // Read the first batch of the TcpServer response bytes. Int32 bytes = stream.Read(data, 0, data.Length); responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes); Console.WriteLine("Received: {0}", responseData); // Close everything. stream.Close(); client.Close(); } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: {0}", e); } catch (SocketException e) { Console.WriteLine("SocketException: {0}", e); } Console.WriteLine("\n Press Enter to continue..."); Console.Read();
相關文章
相關標籤/搜索