如何通过c#中的socket发送文件

我有服务器和客户端控制台应用程序,可以很好地进行通信以及发送一些字符 这是代码……

服务器

public static void Main() { try { IPAddress ipAd = IPAddress.Parse("127.0.0.1"); /* Initializes the Listener */ TcpListener myList = new TcpListener(ipAd, 1234); /* Start Listeneting at the specified port */ myList.Start(); Console.WriteLine("The server is running at port 8001..."); Console.WriteLine("The local End point is :" + myList.LocalEndpoint); Console.WriteLine("Waiting for a connection....."); Socket s = myList.AcceptSocket(); Console.WriteLine("Connection accepted from " + s.RemoteEndPoint); byte[] b = new byte[100]; int k = s.Receive(b); Console.WriteLine("Recieved..."); for (int i = 0; i < k; i++) Console.Write(Convert.ToChar(b[i])); ASCIIEncoding asen = new ASCIIEncoding(); s.Send(asen.GetBytes("The string was recieved by the server.")); Console.WriteLine("\nSent Acknowledgement"); /* clean up */ s.Close(); myList.Stop(); } catch (Exception e) { Console.WriteLine("Error..... " + e.StackTrace); } } 

客户

 public static void Main() { try { TcpClient tcpclnt = new TcpClient(); Console.WriteLine("Connecting..."); tcpclnt.Connect("127.0.0.1", 1234); Console.WriteLine("Connected"); Console.Write("Enter the string to be transmitted: "); String str = Console.ReadLine(); Stream stm = tcpclnt.GetStream(); ASCIIEncoding asen = new ASCIIEncoding(); byte[] ba = asen.GetBytes(str); Console.WriteLine("Transmitting..."); stm.Write(ba, 0, ba.Length); byte[] bb = new byte[100]; int k = stm.Read(bb, 0, 100); for (int i = 0; i < k; i++) Console.Write(Convert.ToChar(bb[i])); tcpclnt.Close(); } catch (Exception e) { Console.WriteLine("Error... " + e.StackTrace); } } 

现在,我需要添加代码算法,该算法将通过相同的应用程序发送文件。 要实现的关键是在客户端中使用Socket.Send。 我不确定该文件的序列化和反序列化。

任何暗示,建议和建议都是值得欢迎的。 谢谢。

根据要求,您可以在客户端执行以下操作 – 正如本文所建议的那样,除了您可能要考虑将同步Send部分更改为异步Send如下所示:

 clientSocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, endSendCallback, clientSocket); //use async 

你的回调可能如下所示:

 private static void endSendCallback(IAsyncResult ar) { try { SocketError errorCode; int result = clientSocket.EndSend(ar, out errorCode); Console.WriteLine(errorCode == SocketError.Success ? "Successful! The size of the message sent was :" + result.ToString() : "Error with error code: " + errorCode.ToString() //you probably want to consider to resend if there is error code, but best practice is to handle the error one by one ); } catch (Exception e) { //exception Console.WriteLine("Unhandled EndSend Exception! " + e.ToString()); //do something like retry or just report that the sending fails //But since this is an exception, it probably best NOT to retry } } 

至于上述更改后的完整客户端代码如何:

 using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace TcpClientConsoleApplication { class Program { const int PORT_NO = 2201; const string SERVER_IP = "127.0.0.1"; static Socket clientSocket; //put here static void Main(string[] args) { //Similarly, start defining your client socket as soon as you start. clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); loopConnect(3, 3); //for failure handling string result = ""; do { result = Console.ReadLine(); //you need to change this part if (result.ToLower().Trim() != "exit") { byte[] bytes = Encoding.ASCII.GetBytes(result); //Again, note that your data is actually of byte[], not string //do something on bytes by using the reference such that you can type in HEX STRING but sending thing in bytes clientSocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, endSendCallback, clientSocket); //use async //clientSocket.Send(bytes); use this for sync send } } while (result.ToLower().Trim() != "exit"); } private static void endSendCallback(IAsyncResult ar) { try { SocketError errorCode; int result = clientSocket.EndSend(ar, out errorCode); Console.WriteLine(errorCode == SocketError.Success ? "Successful! The size of the message sent was :" + result.ToString() : "Error with error code: " + errorCode.ToString() //you probably want to consider to resend if there is error code, but best practice is to handle the error one by one ); } catch (Exception e) { //exception Console.WriteLine("Unhandled EndSend Exception! " + e.ToString()); //do something like retry or just report that the sending fails //But since this is an exception, it probably best NOT to retry } } static void loopConnect(int noOfRetry, int attemptPeriodInSeconds) { int attempts = 0; while (!clientSocket.Connected && attempts < noOfRetry) { try { ++attempts; IAsyncResult result = clientSocket.BeginConnect(IPAddress.Parse(SERVER_IP), PORT_NO, endConnectCallback, null); result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(attemptPeriodInSeconds)); System.Threading.Thread.Sleep(attemptPeriodInSeconds * 1000); } catch (Exception e) { Console.WriteLine("Error: " + e.ToString()); } } if (!clientSocket.Connected) { Console.WriteLine("Connection attempt is unsuccessful!"); return; } } private const int BUFFER_SIZE = 4096; private static byte[] buffer = new byte[BUFFER_SIZE]; //buffer size is limited to BUFFER_SIZE per message private static void endConnectCallback(IAsyncResult ar) { try { clientSocket.EndConnect(ar); if (clientSocket.Connected) { clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), clientSocket); } else { Console.WriteLine("End of connection attempt, fail to connect..."); } } catch (Exception e) { Console.WriteLine("End-connection attempt is unsuccessful! " + e.ToString()); } } const int MAX_RECEIVE_ATTEMPT = 10; static int receiveAttempt = 0; private static void receiveCallback(IAsyncResult result) { System.Net.Sockets.Socket socket = null; try { socket = (System.Net.Sockets.Socket)result.AsyncState; if (socket.Connected) { int received = socket.EndReceive(result); if (received > 0) { receiveAttempt = 0; byte[] data = new byte[received]; Buffer.BlockCopy(buffer, 0, data, 0, data.Length); //There are several way to do this according to https://stackoverflow.com/questions/5099604/any-faster-way-of-copying-arrays-in-c in general, System.Buffer.memcpyimpl is the fastest //DO ANYTHING THAT YOU WANT WITH data, IT IS THE RECEIVED PACKET! //Notice that your data is not string! It is actually byte[] //For now I will just print it out Console.WriteLine("Server: " + Encoding.UTF8.GetString(data)); socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); } else if (receiveAttempt < MAX_RECEIVE_ATTEMPT) { //not exceeding the max attempt, try again ++receiveAttempt; socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); } else { //completely fails! Console.WriteLine("receiveCallback is failed!"); receiveAttempt = 0; clientSocket.Close(); } } } catch (Exception e) { // this exception will happen when "this" is be disposed... Console.WriteLine("receiveCallback is failed! " + e.ToString()); } } } } 

有关上述代码如何工作的完整说明(请注意,第7点已更改,而第8点已添加为异步Send ):

客户:

  1. 类似地,将Socket类放在类上下文而不是方法上下文中,并在启动程序时立即对其进行初始化

     const int PORT_NO = 2201; const string SERVER_IP = "127.0.0.1"; static Socket clientSocket; //put here static void Main(string[] args) { //Similarly, start defining your client socket as soon as you start. clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //your other main routines } 
  2. 然后开始通过BeginConnect连接。 我通常会通过LoopConnect进一步处理这样的故障处理。

     static void loopConnect(int noOfRetry, int attemptPeriodInSeconds) { int attempts = 0; while (!clientSocket.Connected && attempts < noOfRetry) { try { ++attempts; IAsyncResult result = clientSocket.BeginConnect(IPAddress.Parse(SERVER_IP), PORT_NO, endConnect, null); result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(attemptPeriodInSeconds)); System.Threading.Thread.Sleep(attemptPeriodInSeconds * 1000); } catch (Exception e) { Console.WriteLine("Error: " + e.ToString()); } } if (!clientSocket.Connected) { Console.WriteLine("Connection attempt is unsuccessful!"); return; } } 
  3. 与您对服务器的操作类似的概念BeginAccept您需要为您使用的BeginConnect定义endConnectCallback 。 但在这里, 需要重新调用BeginAccept 服务器不同 ,一旦连接,您不需要执行任何新的BeginConnect因为您只需要连接一次

  4. 您可能想要声明buffer等。然后,在连接之后,不要忘记下一个BeginReceive来处理消息检索部分(与服务器类似)

     private const int BUFFER_SIZE = 4096; private static byte[] buffer = new byte[BUFFER_SIZE]; //buffer size is limited to BUFFER_SIZE per message private static void endConnectCallback(IAsyncResult ar) { try { clientSocket.EndConnect(ar); if (clientSocket.Connected) { clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), clientSocket); } else { Console.WriteLine("End of connection attempt, fail to connect..."); } } catch (Exception e) { Console.WriteLine("End-connection attempt is unsuccessful! " + e.ToString()); } } 
  5. 当然,您需要定义您的receiveCallback ,就像您为服务器所做的那样。 是的,正如您所猜测的那样,它几乎与您为服务器所做的完全相同!

  6. 您可以使用数据执行任何操作。 请注意,您收到的数据实际上是byte[] ,而不是string 。 所以你可以用它做任何事情。 但是,例如 ,我将使用string来显示。

     const int MAX_RECEIVE_ATTEMPT = 10; static int receiveAttempt = 0; private static void receiveCallback(IAsyncResult result) { System.Net.Sockets.Socket socket = null; try { socket = (System.Net.Sockets.Socket)result.AsyncState; if (socket.Connected) { int received = socket.EndReceive(result); if (received > 0) { receiveAttempt = 0; byte[] data = new byte[received]; Buffer.BlockCopy(buffer, 0, data, 0, data.Length); //copy the data from your buffer //DO ANYTHING THAT YOU WANT WITH data, IT IS THE RECEIVED PACKET! //Notice that your data is not string! It is actually byte[] //For now I will just print it out Console.WriteLine("Server: " + Encoding.UTF8.GetString(data)); socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); } else if (receiveAttempt < MAX_RECEIVE_ATTEMPT) { //not exceeding the max attempt, try again ++receiveAttempt; socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); } else { //completely fails! Console.WriteLine("receiveCallback is failed!"); receiveAttempt = 0; clientSocket.Close(); } } } catch (Exception e) { // this exception will happen when "this" is be disposed... Console.WriteLine("receiveCallback is failed! " + e.ToString()); } } 
  7. 下一个(在最后一个之前) - 是的,再次,正如您已经猜到的那样,您只需要在主程序上执行某些操作 - 假设您要将其用于BeginSend数据。 因为您使用Console但是希望它以byte[]发送,所以您需要进行转换(请参阅链接post的服务器9中的说明)。

     static void Main(string[] args) { //Similarly, start defining your client socket as soon as you start. clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); loopConnect(3, 3); //for failure handling string result = ""; do { result = Console.ReadLine(); //you need to change this part if (result.ToLower().Trim() != "exit") { byte[] bytes = Encoding.ASCII.GetBytes(result); //Again, note that your data is actually of byte[], not string //do something on bytes by using the reference such that you can type in HEX STRING but sending thing in bytes clientSocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, endSendCallback, clientSocket); //use async //clientSocket.Send(bytes); use this for sync send } } while (result.ToLower().Trim() != "exit"); } 
  8. 最后,在最后,你只需要声明异步EndSend回调函数,你就完成了!

     private static void endSendCallback(IAsyncResult ar) { try { SocketError errorCode; int result = clientSocket.EndSend(ar, out errorCode); Console.WriteLine(errorCode == SocketError.Success ? "Successful! The size of the message sent was :" + result.ToString() : "Error with error code: " + errorCode.ToString() //you probably want to consider to resend if there is error code, but best practice is to handle the error one by one ); } catch (Exception e) { //exception Console.WriteLine("Unhandled EndSend Exception! " + e.ToString()); //do something like retry or just report that the sending fails //But since this is an exception, it probably best NOT to retry } } 

File.ReadAllBytes(字符串路径)将为您提供文件的字节数组。
File.WriteAllBytes(string path,byte [] bytes)将把它写入磁盘。
帮助区分文件/命令/状态/等。 您可以在前面添加一个字节标题的消息内容。 枚举:字节可能在这里派上用场。

您只需要将文件作为字节数组读取,然后通过线路发送该字节数组

 var bytes = File.ReadAllBytes(path); stm.Write(ba, 0, ba.Length);