Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
430 views
in Technique[技术] by (71.8m points)

timeout - C# How do I stop a tcpClient.Connect() process when i'm ready for the program to end? It just sits there for like 10 seconds!

This is one of my first issues. Whenever I exit out the program, tcpClient.Connect() takes forever to close. I've tried a ton of things, and none of them seem to work.

Take a look at the CreateConnection() thread, if the client isn't connected yet... and I close the program, it takes forever to close. If it IS connected, it closes immediately. I know this can be done with some kind of timeout trick, but i've tried a few and none of them worked.

Please provide a code example if you can.

Also, is there any good tutorial out there for C# on reading/writing the actual bytes with a buffer instead of this version that just does masterServer.writeLine() and masterServer.readline() or are they both just as efficient?

If you see anything else to help me improve this... by all means, go ahead. I'm trying to teach myself how to do this and I have no help, so don't let me go on doing something wrong if you see it!!! Thanks guys!

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

namespace RemoteClient
{
    public partial class Form1 : Form
    {
        private int MyPort = 56789;
        private IPAddress myIp = IPAddress.Parse("210.232.115.79");
        private IPAddress serverIp = IPAddress.Parse("72.216.18.77"); // Master Server's IP Address
        public static TcpClient masterServer = new TcpClient();

        private StreamWriter responseWriter;
        private StreamReader commandReader;

        private Thread connectionThread;
        private Thread commandsThread;

        private bool RequestExitConnectionThread { get; set; }

        private delegate void AddMessageDelegate(string message, int category);
        private delegate void ConnectedDelegate();

        private bool isConnected { get; set; }

        public Form1()
        {
            InitializeComponent();
            isConnected = false;
        }

        private void LogMessage(string message, int category)
        {
            if (category == 1)
            {
                ListViewItem item = new ListViewItem(message);
                item.BackColor = Color.LightGreen;
                item.UseItemStyleForSubItems = true;
                Log.Items.Add(item).SubItems.Add(DateTime.Now.ToString());
            }
            if (category == 2)
            {
                ListViewItem item = new ListViewItem(message);
                item.BackColor = Color.Orange;
                item.UseItemStyleForSubItems = true;
                Log.Items.Add(item).SubItems.Add(DateTime.Now.ToString());
            }
            if (category == 3)
            {
                ListViewItem item = new ListViewItem(message);
                item.BackColor = Color.Yellow;
                item.UseItemStyleForSubItems = true;
                Log.Items.Add(item).SubItems.Add(DateTime.Now.ToString());
            }
            if (category == 0)
            {
                Log.Items.Add(message).SubItems.Add(DateTime.Now.ToString());
            }
        }

        private void Connected()
        {
            LogMessage("Found and Accepted Master Server's connection. Waiting for reply...",1);
            Status.Text = "Connected!";
            Status.ForeColor = Color.Green;

            commandsThread = new Thread(new ThreadStart(RecieveCommands));

            sendClientInfo();
        }

        private void exitButton_Click(object sender, EventArgs e)
        {
            Disconnect();
            exitButton.Enabled = false;
            exitButton.Text = "Closing...";

            if (connectionThread != null)
            {
                while (connectionThread.IsAlive)
                {
                    Application.DoEvents();
                }
            }

            this.Close();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Connect();
        }

        private void Disconnect()
        {
            RequestExitConnectionThread = true;

            if (masterServer != null)
                masterServer.Close();

            if (connectionThread != null)
                connectionThread.Abort();

            LogMessage("Closing Client. Please wait while Program threads end.", 2);
        }

        private void Disconnected()
        {
            Status.Text = "Disconnected";
            Status.ForeColor = Color.Red;
            Connect();
        }

        private void Connect()
        {
            LogMessage("Attempting to connect to Master Server...", 1);

            connectionThread = new Thread(new ThreadStart(CreateConnection));
            connectionThread.Start();
        }

        private void CreateConnection()
        {
            int i = 1;
            bool success = false;

            while (!success)
            {
                try
                {
                    using (masterServer = new TcpClient())
                    {
                        IAsyncResult result = masterServer.BeginConnect(serverIp, MyPort, null, null);
                        success = result.AsyncWaitHandle.WaitOne(1000, false);
                    }

                    if (success)
                    {
                        BeginInvoke(new ConnectedDelegate(this.Connected), new object[] {});
                        break;
                    }
                    else
                    {
                        Thread.Sleep(2000);
                        BeginInvoke(new AddMessageDelegate(LogMessage), new object[] { "Connection Retry # " + i.ToString() + ". Master Server hasn't been started yet.", 3 });
                    }
                }
                catch
                {
                    MessageBox.Show("Error!");
                }
                i++;
            }

        }

        private void RecieveCommands()
        {
            MessageBox.Show("Hello!");
            commandReader = new StreamReader(masterServer.GetStream());

            string CommandResponse = commandReader.ReadLine();
            string Command = null;

            if (CommandResponse != null)
                MessageBox.Show("Recieved Command that was NOT null!");

            if (CommandResponse != null)
            {
                MessageBox.Show("Recieved null response!");
                BeginInvoke(new AddMessageDelegate(LogMessage), new object[] { "Disconnected From Master Server. Reason: Recieved Null response.", 1 });
                Disconnected();
            }
            else if (CommandResponse.StartsWith("0"))
            {
                MessageBox.Show("Recieved 0 as a response!");
                Command = CommandResponse.Substring(2).Trim();

                isConnected = false;
                BeginInvoke(new AddMessageDelegate(LogMessage), new object[] { "Disconnected From Master Server. Reason: " + Command, 1 });
            }
            else if (CommandResponse.StartsWith("1"))
            {
                MessageBox.Show("Recieved 1 as a response!");
                isConnected = true;
                BeginInvoke(new AddMessageDelegate(LogMessage), new object[] { "Connected to Master Server Successfully.", 1 });
            }
        }


        //************************** RESPONSE'S BELOW HERE ************************* \

        private void sendClientInfo()
        {
            responseWriter = new StreamWriter(masterServer.GetStream());

            responseWriter.WriteLine(myIp.ToString());
            responseWriter.Flush();
        }

    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Sorry, after testing it: NO, it does not use an async waithandle, it blocks the process :(

I prefer this solution, which also blocks the process but only by the period you specify, in this case 5 seconds:

using (TcpClient tcp = new TcpClient())  
{  
    IAsyncResult ar = tcp.BeginConnect("127.0.0.1", 80, null, null);  
    System.Threading.WaitHandle wh = ar.AsyncWaitHandle;  
    try 
    {  
       if (!ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5), false))  
       {  
           tcp.Close();  
           throw new TimeoutException();  
       }  

        tcp.EndConnect(ar);  
    }  
    finally 
    {  
        wh.Close();  
    }  
}

From: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/2281199d-cd28-4b5c-95dc-5a888a6da30d

The following example uses both async connection and async timeout control:

var tcp = new TcpClient();
var ar = tcp.BeginConnect(Ip, Port, null, null);
Task.Factory.StartNew(() =>
{
    var wh = ar.AsyncWaitHandle;
    try
    {
        if (!ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5), false))
        {
            // The logic to control when the connection timed out
            tcp.Close();
            throw new TimeoutException();
        }
        else
        {
            // The logic to control when the connection succeed.
            tcp.EndConnect(ar);
         }
     }
     finally
     {
         wh.Close();
     }
});

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...