如何在C#中通过套接字发送文件

费里德·塞多维奇(FeridSejdović)

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

服务器

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. 然后开始通过进行连接ASync 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,你需要定义endConnectCallbackASync BeginConnect使用。但是在这里,需要重新调用的服务器不同BeginAccept,连接后,您不需要做任何新操作,BeginConnect因为您只需要连接一次

  4. 您可能想要声明buffer等。然后,在连接之后,不要忘记ASync 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因此,您可以执行任何操作。但是例如,我将仅使用stringdisplay进行显示。

    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[],所以您需要进行转换(请参阅链接文章的服务器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
        }
    }
    

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在C中通过TCP套接字通过HTTP发送文件?

来自分类Dev

如何在C中通过TCP套接字通过HTTP发送文件?

来自分类Dev

如何通过c中的套接字发送多个文件?

来自分类Dev

如何通过 Dart 中的套接字发送文件

来自分类Dev

如何通过套接字发送PDF文件?

来自分类Dev

如何在C中通过udp套接字发送整数数组?

来自分类Dev

通过套接字在C#中传输半文件?

来自分类Dev

通过Python中的TCP套接字发送文件

来自分类Dev

通过C#中的TCP套接字方法发送位类型数据

来自分类Dev

使用C中的套接字通过TCP发送音频文件

来自分类Dev

如何通过python中的套接字发送数组

来自分类Dev

如何通过python中的套接字发送字节?

来自分类Dev

通过C中的TCP套接字发送结构

来自分类Dev

通过C中的套接字发送空终止符

来自分类Dev

如何通过C中的套接字一起发送两个缓冲区?

来自分类Dev

如何使用套接字C / C ++批量发送文件?

来自分类Dev

通过TCP套接字发送多个文件

来自分类Dev

通过套接字发送大型JSON文件

来自分类Dev

Python通过套接字发送文件

来自分类Dev

C#套接字如何知道何时发送某些数据

来自分类Dev

如何通过套接字发送HTTPS请求?

来自分类Dev

通过Java中的套接字发送对象

来自分类Dev

通过Java中的套接字发送链表

来自分类Dev

如何通过Java中的套接字编程传输zip文件?

来自分类Dev

如何通过Java中的套接字编程传输zip文件?

来自分类Dev

使用 C# 通过套接字发送和接收图像 | 使用 C# 共享屏幕

来自分类Dev

如何在Python中完成套接字文件传输?

来自分类Dev

如何在Python中完成套接字文件传输?

来自分类Dev

在C ++中通过套接字发送图片(发送func),但不能接收完成(Windows)!

Related 相关文章

  1. 1

    如何在C中通过TCP套接字通过HTTP发送文件?

  2. 2

    如何在C中通过TCP套接字通过HTTP发送文件?

  3. 3

    如何通过c中的套接字发送多个文件?

  4. 4

    如何通过 Dart 中的套接字发送文件

  5. 5

    如何通过套接字发送PDF文件?

  6. 6

    如何在C中通过udp套接字发送整数数组?

  7. 7

    通过套接字在C#中传输半文件?

  8. 8

    通过Python中的TCP套接字发送文件

  9. 9

    通过C#中的TCP套接字方法发送位类型数据

  10. 10

    使用C中的套接字通过TCP发送音频文件

  11. 11

    如何通过python中的套接字发送数组

  12. 12

    如何通过python中的套接字发送字节?

  13. 13

    通过C中的TCP套接字发送结构

  14. 14

    通过C中的套接字发送空终止符

  15. 15

    如何通过C中的套接字一起发送两个缓冲区?

  16. 16

    如何使用套接字C / C ++批量发送文件?

  17. 17

    通过TCP套接字发送多个文件

  18. 18

    通过套接字发送大型JSON文件

  19. 19

    Python通过套接字发送文件

  20. 20

    C#套接字如何知道何时发送某些数据

  21. 21

    如何通过套接字发送HTTPS请求?

  22. 22

    通过Java中的套接字发送对象

  23. 23

    通过Java中的套接字发送链表

  24. 24

    如何通过Java中的套接字编程传输zip文件?

  25. 25

    如何通过Java中的套接字编程传输zip文件?

  26. 26

    使用 C# 通过套接字发送和接收图像 | 使用 C# 共享屏幕

  27. 27

    如何在Python中完成套接字文件传输?

  28. 28

    如何在Python中完成套接字文件传输?

  29. 29

    在C ++中通过套接字发送图片(发送func),但不能接收完成(Windows)!

热门标签

归档