c# - 使用 C# 鼠标事件从服务器向客户端发送标志

标签 c# sockets asynchronous callback mouseevent

我在 C# 中使用套接字,以便将数据从服务器发送到客户端计算机。事实上,我已经创建了一个捕捉器,它捕捉来自 3 台不同机器的 kinect 流。我想生成服务器和客户端通信,以便将信号从服务器发送到其余设备,以便开始和停止录制过程。我想左键单击发送消息以开始录制,右键单击以停止录制。我的代码如下:

public Form1()
{
    InitializeComponent();
    this.MouseClick += mouseClick1;


    Thread thread = new Thread(() => StartServer(message));
    thread.Start();  // server is begining
}

private void mouseClick1(object sender, MouseEventArgs e)
{

    if (e.Button == MouseButtons.Left)
    {
       message = "start";  
        try
        {
                obj = new Capturer(dirPath + name + "_" + surname, 20);
        }
        catch (Exception e1)
        {
            Console.WriteLine("The process failed: {0}", e1.ToString());
        }
        if (clientSockets.Count > 0)
        {
            Thread.Sleep(10);
            foreach (Socket socket1 in clientSockets)
                socket1.Send(Encoding.ASCII.GetBytes(message)); //send everything to all clients as bytes
        }
        else
        {

            serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null); //to receive another client
        }

    }
    else if (e.Button == MouseButtons.Right)
    {
        message = "stop";
        obj.flag2 = true;

        if (clientSockets.Count > 0)
        {
            Thread.Sleep(10);
            foreach (Socket socket1 in clientSockets)
                socket1.Send(Encoding.ASCII.GetBytes(message)); //send everything to all clients as bytes
        }
        else
        {

            serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null); //to receive another client
        }
    }
}

public void StartServer(String message) {

    serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    serverSocket.Bind(new IPEndPoint(IPAddress.Any, PORT_NO));
    serverSocket.Listen(4); //the maximum pending client, define as you wish
    serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null);
    string result = "";
    do
    {
        result ="asdf";
    } while (result.ToLower().Trim() != "exit");
}
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 List<Socket> clientSockets = new List<Socket>(); //may be needed by you 
private static void acceptCallback(IAsyncResult result)
{ //if the buffer is old, then there might already be something there...
    Socket socket = null;
    try
    {

        socket = serverSocket.EndAccept(result); // The objectDisposedException will come here... thus, it is to be expected!
        //Do something as you see it needs on client acceptance
        clientSockets.Add(socket);
        socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket);


        string msg = "start";
        //socket.Send(Encoding.ASCII.GetBytes(msg));

        if (clientSockets.Count > 0)
        {
            Thread.Sleep(10);
            foreach (Socket socket1 in clientSockets)
                socket1.Send(Encoding.ASCII.GetBytes(msg)); //send everything to all clients as bytes
        }
        else
        {

            serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null); //to receive another client
        }
    }
    catch (Exception e)
    { // this exception will happen when "this" is be disposed...        
        //Do something here             
        Console.WriteLine(e.ToString());
    }
}

const int MAX_RECEIVE_ATTEMPT = 10;
static int receiveAttempt = 0; //this is not fool proof, obviously, since actually you must have multiple of this for multiple clients, but for the sake of simplicity I put this
private static void receiveCallback(IAsyncResult result)
{
    Socket socket = null;
    try
    {
        socket = (Socket)result.AsyncState; //this is to get the sender
        if (socket.Connected)
        { //simple checking
            int received = socket.EndReceive(result);
            if (received > 0)
            {
                byte[] data = new byte[received]; //the data is in the byte[] format, not string!
                Buffer.BlockCopy(buffer, 0, data, 0, data.Length); //There are several way to do this according to http://stackoverflow.com/questions/5099604/any-faster-way-of-copying-arrays-in-c in general, System.Buffer.memcpyimpl is the fastest
                //DO SOMETHING ON THE DATA int byte[]!! Yihaa!!
                Console.WriteLine(Encoding.UTF8.GetString(data)); //Here I just print it, but you need to do something else                     

                //Message retrieval part
                //Suppose you only want to declare that you receive data from a client to that client
                string msg = "I receive your message on: " + DateTime.Now;
                socket.Send(Encoding.ASCII.GetBytes(msg)); //Note that you actually send data in byte[]
                Console.WriteLine("I sent this message to the client: " + msg);

                receiveAttempt = 0; //reset receive attempt
                //socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); //repeat beginReceive
            }
            else if (receiveAttempt < MAX_RECEIVE_ATTEMPT)
            { //fail but not exceeding max attempt, repeats
                ++receiveAttempt; //increase receive attempt;
                socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), socket); //repeat beginReceive
            }
            else
            { //completely fails!
                Console.WriteLine("receiveCallback fails!"); //don't repeat beginReceive
                receiveAttempt = 0; //reset this for the next connection
            }
        }
    }
    catch (Exception e)
    { // this exception will happen when "this" is be disposed...
        Console.WriteLine("receiveCallback fails with exception! " + e.ToString());
    }
}

如何将标志解析到服务器中,以便在客户端发送该值?是否可以在此处更改服务器功能的静态类型?现在,代码开始服务器,它只向客户端发送字符串“start”。如何发送 bool 标志的字符串消息?我的问题在于回调函数的静态类型。是否可以将消息作为参数添加到 AsyncCallBack 中:

serverSocket.BeginAccept(new AsyncCallback(acceptCallback), null); 

最佳答案

首先,关于MouseClick 事件。由于您对事件具有排他性资格(即一次左键单击和另一次右键单击),您可以将它们组合成一个事件

public Form1()
{
    InitializeComponent();
    this.MouseClick += mouseClick1; //one event is enough

    Thread thread = new Thread(() => StartServer(message));
    thread.Start();  // server is begining
}

private void mouseClick1(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        try
        {
            obj = new Capturer(dirPath + name + "_" + surname, 20); //captures the kinect streams
        }
        catch (Exception e1)
        {
            Console.WriteLine("The process failed: {0}", e1.ToString());
        }
    } 
    else if (e.Button == MouseButtons.Right)
    {
        obj.flag2 = true; // flag that handle the recording, true value stops the recording, possible I want that value to be send to the client in order the same thing happen.
    }
}

一切都会好起来的。

接下来,回答您的问题:

Q: How can I parse the flag into the server, in order to send that value in the clients?

A: in your mouseClick1 event, simply use sync send which you do in your accept callback, change the msg with something else (say byte[] val = new byte[] { 1 };)

foreach (Socket socket1 in clientSockets) //Do this in your `if (e.Button == Mouse.Left and Mouse.Right) blocks
    socket1.Send(Encoding.ASCII.GetBytes(msg));

Q: Is it possible to change here the static type of server functions?

A: Yes, definitely! it is windows form, you do not need to use static type at all! Unlike the Console App in your previous question. I would even suggest you to make nothing static whenever possible

Q: As it is now the code begin the server which send just the string "start" to the clients. How can I send the string message of a bool flag?

A: since you use socket, you cannot really send bool flag so to speak. You will send byte[]. But you can always check in your client implementation. If the byte[] is of certain value, simply change it to bool. For instance, consider of sending just 1 or 0 from your server. Then in your client endReceiveCallback, you could simply check the data coming and see if it is 1 then it is true, and if it is 0 then it is false

Q: My issue lies in the static type of my callback functions. Is it possible to add as an argument the message for example in the AsyncCallBack

A: this is winform, you could get rid of all static var! And yes, just pass it as replacement of the null in your Begin callback. Then you pass the object too.

//Change null with something else
serverSocket.BeginAccept(new AsyncCallback(acceptCallback), myobj);

Then in your acceptCallback, take your object by using the IAsyncResult.AsyncState

关于c# - 使用 C# 鼠标事件从服务器向客户端发送标志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34767502/

相关文章:

c# - 在运行时使用连接字符串

c# - 来自 PowerBuilder 的 DLL 调用

c# - 如何读取字节数组中的单个 BIT?

java - 接收图像并使用 TCP 套接字显示它? (安卓)

c - 如何编写重发数据包的代理程序?

Javascript:其他异步函数中的异步嵌套函数给出了意外的结果

.net - 我什么时候应该使用 UdpClient.BeginReceive?什么时候应该在后台线程上使用 UdpClient.Receive?

c# - 保护 foreach 循环免受 null 影响的更智能方法

c++ - WSAGetLastError 返回 WSAENOTSOCK - 原因?

php - 使用 guzzle 发送异步请求而不等待响应