使用c#表单中的异步客户端套接字发送和接收

时间:2014-05-30 10:08:22

标签: c# tcp tcpclient asyncsocket beginreceive

我正在尝试连接到远程服务器,登录,然后向其发送数据并使用C#表单应用程序从中接收数据。最初我写了一个控制台应用程序,工作正常,但我需要使用表单。问题是表单应用程序中的BeginSendBeginReceive方法无效。

当我的套接字第一次连接到它(成功)时,我从远程服务器收到一条消息,而我的ConnectionStatusTest显示我仍然连接。但似乎在我向其发送数据之前,连接被丢弃了。来自服务器的原始消息再次显示(而不是我想要接收的新消息),然后显示SendDataExceptionReceiveDataException消息框,而ConnectionStatusTest告诉我我'我已经不再联系了。

这是我的代码:

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ServerForm
{
    public partial class LoginForm : Form
    {
        public LoginForm()
        {
            InitializeComponent();
        }

    Socket tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
    ProtocolType.Tcp);

    public class StateObject
    {
        public Socket clientSocket = null;
        public const int recvBufferSize = 1024;
        public byte[] recvbuffer = new byte[recvBufferSize];
        public StringBuilder sb = new StringBuilder();
    }

    private static ManualResetEvent connectionCompleted = new ManualResetEvent(false);
    private static ManualResetEvent sendCompleted = new ManualResetEvent(false);
    private static ManualResetEvent recvCompleted = new ManualResetEvent(false);

    private static String response = String.Empty;

    private void LoginForm_Shown(object sender, EventArgs e)
    {
        try
        {
            IHostEntry ipHost = Dns.GetHostEntry("*server's web address*");
            IPAddress serverIP = ipHost.AddressList[0];
            int port = 7500;
            IPEndPoint remoteEP = new IPEndPoint(serverIP, port);

            tcpSocket.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), tcpSocket);
            connectionCompleted.WaitOne();
            tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
            //tcpSocket.IOControl(IOControlCode.KeepAliveValues, inValue, outValue);

            AsyncSendReceiveData.ReceiveData(tcpSocket);
            AsyncSendReceiveData.recvCompleted.WaitOne();
        }
    }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "LoginForm_Shown Exception");
        }
    }

    private static void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            Socket tcpSocket = (Socket)ar.AsyncState;
            tcpSocket.EndConnect(ar);
            if (tcpSocket.Connected == true)
            {
                MessageBox.Show(String.Format("Socket connected to server ({0})", 
                tcpSocket.RemoteEndPoint.ToString()));
            }

            connectionCompleted.Set();
        }
        catch (Exception e)
        {
            MessageBox.Show(e.Message, "ConnectCallback Exception");
        }
    }

    private void passText_KeyPress(object sender, KeyPressEventArgs e)
    {
        if (e.KeyChar == (char)13)
        {
            try
            {
                string usernameString = userText.Text.ToUpper();
                string passwordString = passText.Text.ToUpper();
                string loginDetails = String.Format("LOGIN {0}:{1}",
                usernameString, passwordString);

                string data = loginDetails;

                AsyncSendReceiveData.SendData(tcpSocket, data);
                AsyncSendReceiveData.sendCompleted.WaitOne();

                AsyncSendReceiveData.ReceiveData(tcpSocket);
                AsyncSendReceiveData.recvCompleted.WaitOne();

                ConnectionStatusTest();

                string versionString = "VERSION 3";
                data = versionString;

                AsyncSendReceiveData.SendData(tcpSocket, data);
                AsyncSendReceiveData.sendCompleted.WaitOne();

                AsyncSendReceiveData.ReceiveData(tcpSocket);
                AsyncSendReceiveData.recvCompleted.WaitOne();
            }
            catch (SocketException ex)
            {
                MessageBox.Show(ex.Message, "KeyPress Exception");
            }
        }
    }

    public class AsyncSendReceiveData
    {
        public static ManualResetEvent sendCompleted = new ManualResetEvent(false);
        public static ManualResetEvent recvCompleted = new ManualResetEvent(false);

        public static void ReceiveData(Socket tcpSocket)
        {
            try
            {
                StateObject stateobj = new StateObject();
                stateobj.clientSocket = tcpSocket;

                tcpSocket.BeginReceive(stateobj.recvbuffer, 0,
                StateObject.recvBufferSize, 0,
                new AsyncCallback(ReceiveCallback), stateobj);
            }
            catch (SocketException e)
            {
                MessageBox.Show(e.Message + "\n" + "Exception occurred" + 
                e.StackTrace.ToString(), "ReceiveData Exception");
            }
        }

        private static void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                StateObject stateobj = (StateObject)ar.AsyncState;
                Socket tcpSocket = stateobj.clientSocket;

                int bytesRead = tcpSocket.EndReceive(ar);
                if (bytesRead > 0)  //This if statement seems to cause slow connection.
                {
                    //Adds more data received to sb                  
                    stateobj.sb.Append(Encoding.ASCII.GetString(stateobj.recvbuffer,
                    0, bytesRead));

                    //Get the rest of the data, if there is any more.
                    tcpSocket.BeginReceive(stateobj.recvbuffer, 0,
                    StateObject.recvBufferSize, 0,
                    new AsyncCallback(ReceiveCallback), stateobj);
                }
                else
                {
                    if (stateobj.sb.Length > 1)
                    {
                        response = stateobj.sb.ToString();
                    }
                    recvCompleted.Set();
                    MessageBox.Show(response);
                }                    
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, "ReceiveCallback Exception");
            }
        }

        public static void SendData(Socket tcpSocket, String data)
        {
            try
            {
                byte[] sendDataBytes = Encoding.ASCII.GetBytes(data);
                tcpSocket.BeginSend(sendDataBytes, 0, sendDataBytes.Length,
                SocketFlags.None, new AsyncCallback(SendCallback), tcpSocket);
            }
            catch (SocketException e)
            {
                MessageBox.Show(e.Message + "\n" + "Exception occurred" +
                e.StackTrace.ToString(), "SendData Exception");
            }
        }

        private static void SendCallback(IAsyncResult ar)
        {
            try
            {
                Socket tcpSocket = (Socket)ar.AsyncState;
                tcpSocket.EndSend(ar);
                sendCompleted.Set();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, "SendCallback Exception");
            }
        }
    }

    public void ConnectionStatusTest()
    {
        try
        {
            byte[] tmp = new byte[1];
            bool blockingState = tcpSocket.Blocking;
            tcpSocket.Blocking = false;
            tcpSocket.Send(tmp, 0, 0, SocketFlags.None);
        }
        catch (SocketException SockEx)
        {
            if (SockEx.NativeErrorCode.Equals(10035))
                MessageBox.Show("Still connected, but the send would block");
            else
            {
                MessageBox.Show(String.Format("Disconnected: error code {0}",
                SockEx.NativeErrorCode.ToString()));
            }
        }
        finally
        {
            bool blockingState = tcpSocket.Blocking;
        }
        MessageBox.Show(String.Format("Connected: {0}",
        tcpSocket.Connected.ToString()));

我花了很多时间试图弄清楚为什么BeginSend和BeginReceive方法都不起作用,我想我已经把它缩小到两个方面之一:

  1. passText_KeyPress函数中,data的{​​{1}}部分未作为参数传递给string data = loginDetails函数。因此,SendData功能无法正常工作,并显示SendData。如果这是问题,如何将SendDataException(或其他字符串)传递给loginDetails函数?

  2. 使用控制台应用程序进行连接时,连接,登录或发送或接收数据都没有问题,并且连接不会被删除。但是,当我尝试使用telnet连接时,在大约30秒不活动后从服务器返回一条消息,说"连接到主机丢失"。在我的表单应用程序中,连接似乎在大约30秒后被删除,并且由于某种原因,表单应用程序需要大约25秒来告诉我我已连接。 我已尝试在表单应用程序中使用KeepAlive,但显然默认的TCP KeepAlive期限为2小时。如果这是问题,我怎么能把它改成20秒呢?我读过的所有内容都建议让Visual Studio通过我的防火墙(我试过这个 - 没有运气),或者必须更改注册表项,这似乎有点过于复杂。

  3. 错误消息是"已建立的连接被主机中的软件中止",错误代码为10053,这让我觉得我已经超时了。我当然可能是错的,问题可能是我没有发现的其他问题。我将衷心感谢您的帮助!感谢。


    更新 - 我已经使用同步方法重写了代码(并添加了一个计时器,这样我就可以看到我是否仍然每隔5秒连接一次)。我现在得到两个不同的错误。

    第一个说"无法立即完成非阻塞套接字操作" 并生成错误代码10035 。当我仍然连接到远程服务器时,SendData方法会发生此错误。我认为清除缓冲区可能有所帮助,但这只是意味着我下次尝试阅读时会收到一条空白消息。所以我只能认为我实际上并没有从服务器收到新消息,即使我知道我应该这样做。

    第二个是原始错误 - "已建立的连接已被主机中的软件中止",错误代码10053 - 这发生在{{1}我在30秒后断开连接的方法。我已经在不同的地方阅读过更改Receive属性可能会有所帮助,但我在调用{{1}之前尝试将其设为SendSocket.Blocking方法,既没有帮助。

    关于如何让它发挥作用的任何想法?

    修改后的代码:

    true

0 个答案:

没有答案