插座连接 [英] Socket connections

查看:98
本文介绍了插座连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


关闭插座时出现错误
我不能在同一端口上再次使用它


我的代码是

Hi
i got error during close the socket
i can''t use it again with the same port


my code is

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Net;
using System.Collections;
namespace ChatMulti_ThreadedServerForms
{
    public partial class MultiThreaded_Server : Form
    {
        public Socket connection = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
        private Thread readThread;
        int counter = 0;
        // new
        private Hashtable clients = new Hashtable();
        private Hashtable writers = new Hashtable();
        private delegate void DisplayDelegate(string msg);
        private delegate void DisableInputDelegate(bool flag);
        public string ipaddressstring = "";
        public int portnumber = 0;
        public MultiThreaded_Server()
        {
            InitializeComponent();
        }
        private void MultiThreaded_Server_Load(object sender, EventArgs e)
        {
            
        }
        
        public void RunServer()
        {
            TcpListener listener;
            try
            {
                listener = new TcpListener(IPAddress.Parse(ipaddressstring), portnumber);
                listener.Start();
                DiplayMessage("Waiting For Connections...\r\n");
                
                while (true)
                {
                    connection = listener.AcceptSocket();
                    counter++;
                    Thread clientThraed = new Thread(GetMessages);
                    clients.Add(clientThraed, connection);
                    clientThraed.Start();
                }
            }
            catch (Exception error)
            {
                MessageBox.Show(error.Message);
            }
        }
        public void GetMessages()
        {
            Socket connection = (Socket)clients[Thread.CurrentThread];
            int count = counter;
            NetworkStream socketStream = new NetworkStream(connection);
            BinaryWriter writer = new BinaryWriter(socketStream);
            BinaryReader reader = new BinaryReader(socketStream);
            writers.Add(Thread.CurrentThread, writer);
            DiplayMessage("Connection {" + counter + "} recieved...\r\n");
            writer.Write("SERVER >> Connetion successful...");
            
            DisableInput(false);
            string theReply = "";
            do
            {
                theReply = reader.ReadString();
                DiplayMessage("\r\n" + theReply);
            } while (theReply != "CLIENT >> exit" && connection.Connected);
            DiplayMessage("\r\nClient " + count +" terminated connection...");
            writer.Close();
            reader.Close();
            socketStream.Close();
            connection.Close();
            writers.Remove(Thread.CurrentThread);
            clients.Remove(Thread.CurrentThread);
            DisableInput(true);
        }
        private void MultiThreaded_Server_FormClosing(object sender, FormClosingEventArgs e)
        {
            Environment.Exit(Environment.ExitCode);
        }
        
        private void DiplayMessage(string msg)
        {
            if (Connstatuslbl.InvokeRequired)
            {
                Invoke(new DisplayDelegate(DiplayMessage), new object[] { msg });
                
            }
           
                //Connstatuslbl.Text += msg;
            
        }
        private void DisableInput(bool flag)
        {
            if (textBox2.InvokeRequired)
            {
                Invoke(new DisableInputDelegate(DisableInput), new object[] { flag });
            }
            else
                textBox1.ReadOnly = flag;
        }
        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                
                if (e.KeyCode == Keys.Enter && textBox1.ReadOnly == false)
                {
                    ICollection keys = writers.Keys;
                    foreach (object key in keys)
                    {
                        BinaryWriter writer = (BinaryWriter)writers[key];
                        writer.Write("SERVER >> " + textBox1.Text);
                    }
                    textBox2.Text += "\r\nSERVER >> " + textBox1.Text;
                    if (textBox1.Text == "exit")
                        connection.Close();
                    textBox1.Clear();
                }
            }
            catch (SocketException)
            {
                textBox2.Text += "\r\nError Writing Object...";
            }
        }
        private void connectbtn_Click(object sender, EventArgs e)
        {
                ipaddressstring = Serverip.Text;
                portnumber = Convert.ToInt32(portnum.Text);
                readThread = new Thread(RunServer);
                readThread.Start();
                if (readThread.ThreadState == ThreadState.Running)
                {
                    Connstatuslbl.Text = "Connected";
                }
                else
                {
                    Connstatuslbl.Text = "Connectedasd";
                }
               
              
            
        }
        
		
        private void disconnectbtn_Click(object sender, EventArgs e)
        {
                MessageBox.Show(readThread.ThreadState.ToString());
                connection.Shutdown(SocketShutdown.Both);
                connection.Disconnect(true);
            
        }
        
    }
}




如何关闭此套接字并重复使用?

谢谢..




how to close this socket and reuse it ?

thanks ..

推荐答案

palboy1990写道:
palboy1990 wrote:

如何关闭此套接字并重复使用它吗?

how to close this socket and reuse it ?


哪个插座?

如果不描述错误,那么我们所能做的就是猜测问题所在.

我首先要说的是,没有listener.Stop()listener.Start()匹配,因此服务器将一直运行到应用程序存在为止,并且直到那时才释放端口.服务器线程如何停止运行?

我的第二个问题是do { ... } while (theReply != "CLIENT >> exit" && connection.Connected);不能按预期的方式工作.如果客户端从不发送任何消息,会发生什么?对ReadString的调用只会坐在那里阻塞线程.如果客户端从不发送魔术退出字符串怎么办?

我的第三个猜测是,这个问题被从未发现的异常隐藏了.有一些可以抛出的套接字操作不受任何保护.

我的第四个问题是,单击断开按钮并没有达到预期的效果.看起来它断开了最后一个连接的客户端的连接,但是如果有多个连接,该怎么办?其他连接在哪里断开?

文本框一键按下事件使用相同的注释:它关闭存储在全局变量中的一个套接字,但不关闭其他任何套接字.

这更多的是评论:为什么在表单关闭"事件中调用Environment.Exit?如果那是杀死线程的方式-因为我看不到任何其他信号通知它们退出的方式-那么这是一种不好的做法.使线程退出的标准方法是让它们定期检查标志,以便它们知道何时应停止处理并从其方法返回.或者,将ThreadIsBackground属性设置为true,以使它们不会阻止进程退出.退出表单的正确方法是简单地将其关闭.


另一条评论:有些变量一次可以被多个线程访问.他们确实需要一些同步(例如lock),以便一个线程不会在另一个线程正在使用它们时对其进行修改.
[/EDIT]


另外,在GetMessages方法中,本地Socket变量与类级Socket变量具有相同的名称,这令人困惑.这也可能导致意外行为.
[/EDIT2]


Which socket?

Without describing the error then all we can do is guess what the problem is.

My first would be that there''s no listener.Stop() to match the listener.Start() so the server will run until the app exists and won''t release the port until then. How does the server thread stop running?

My second would be that do { ... } while (theReply != "CLIENT >> exit" && connection.Connected); doesn''t work the way that it''s expected to. What happens if the client never sends anything? That call to ReadString will just sit there blocking the thread. What if the client never sends the magic exit string?

My third guess would be that the problem is hidden by an exception that''s never caught; there are a few socket operations that can throw that aren''t protected by anything.

My fourth is that the disconnect button click doesn''t do what is expected. It looks like it disconnects the last client that connected, but what if more than one connects? Where are the other ones disconnected?

The same comment goes for the Text Box One key down event: it closes the one socket that stored in the global variable but doesn''t close any others.

This one''s more of a comment: why call Environment.Exit in the Form Closing event? If that''s how the threads are being killed - because I don''t see any other way of signaling any of them to exit - then that''s bad practice. The standard way to have threads exit is to have them periodically check a flag so that they know when they should stop processing and return from their methods. Alternatively set the IsBackground property of the Threads to true so that they don''t stop the process from exiting. The proper way to exit from a form is to simply let it close.


Another comment: there are some variables that can be accessed by more than one thread at at time. They really need some synchronization (ex. lock) so that one thread doesn''t modify them while another thread is using them.
[/EDIT]


Also, in the GetMessages method it''s confusing that the local Socket variable has the same name as the class level Socket variable. That might lead to unintended behavior as well.
[/EDIT2]


回应您对我上一篇文章的评论. . .

您仍然没有说过要重用哪个端口,但是我们来了.

类变量:
*不需要类变量connection,将其删除.
*类变量readThread也是可疑的.如果有多个读取线程怎么办?该变量是否曾经初始化为任何东西?
*哈希表是如此.NET 1.1.泛型更好,并且不需要clientswriters作为查找表,List<Socket>就足够了.

对于服务器方法:
In response to your comments to my previous post . . .

You still haven''t said which port you want to reuse but here we go.

Class variables:
* There''s no need for the class variable connection, get rid of it.
* The class variable readThread is questionable as well. What if there are multiple read threads? Is that variable ever initialized to anything?
* Hashtables are sooooo .NET 1.1. Generics are better and there''s no need for clients or writers to be lookup tables, a List<Socket> will suffice.

For the server method:
private volatile bool runServer = false;
public void RunServer()
{
    TcpListener listener = new TcpListener(IPAddress.Parse(ipaddressstring), portnumber);
    try
    {
        listener.Start();
        DiplayMessage("Waiting For Connections...\r\n");
        // look for connections until we're told to stop
        while (runServer)
        {
            // if a client is trying to connect . . .
            if (listener.Pending())
            {
                // accept it
                Socket connection = listener.AcceptSocket();
                // other threads may want to access this list at the same time so lock it
                lock (clients)
                {
                    clients.Add(connection);
                }
                // chuck the client off to another thread for monitoring
                Thread clientThraed = new Thread(GetMessages);
                clientThraed.IsBackground = true; // <-- important
                clientThraed.Start(connection); // pass the socket as a parameter instead of using a lookup table
            }
            else // otherwise . . .
            {
                // sleep a bit so that we don't peg the processor
                Thread.Sleep(250);
            }
        }
    }
    catch (Exception error)
    {
        // use error.ToString() instead of error.Message, it shows more info
        MessageBox.Show(error.ToString());
    }
    finally
    {
        // stop the listener, this will allow another socket to bind to the port it was
        // using now that the listener is done with it
        listener.Stop();
    }
    return;
}


内联注释应能解释其中的大部分内容,但重点是:
*除非知道不会阻塞,否则它不会调用任何阻塞方法(AcceptSocket)
*它检查布尔值(runServer)以查看是否应继续运行
*它在方法退出之前调用listener.Stop()
*它使读取线程创建一个后台线程
*它用lock保护clients,因为它同时被主线程和服务器线程访问
*将套接字作为参数传递给GetMessages

GetMessages现在带有一个参数,因此它应该像这样开始:


Inline comments should explain most of it but the highlights are that:
* it doesn''t call any blocking methods (AcceptSocket) unless it knows it won''t block
* it checks a boolean (runServer) to see if it should continue running
* it calls listener.Stop() before the method exits
* it makes the read thread that it creates a background thread
* it protects clients with a lock since it''s accessed by both the main and server threads
* it passes the socket to GetMessages as a param

GetMessages now takes a parameter so it should start like this:

private void GetMessages(object obj)
{
    Socket connection = obj as Socket;

    // the rest of the method . . .
}



所有这些主体都应用于重写GetMessages方法,以便它锁定由多个线程访问并协作存在的资源.另外,我认为NetworkStream需要在完成后Dispose() d.

现在,这会更改您的应用程序中的许多其他内容:
*在启动服务器线程之前(在连接按钮回调中),将runServer设置为true.
*要停止服务器线程,只需将runServer设置为false,并且RunServer方法将退出-这应该替换对Environment.Exit的调用. *如果客户端尚未发送魔术字符串,则应该通过将bool设置为false来告诉它们退出,以杀死读取线程.
*在关闭全局connection的位置之前,现在应该遍历clients中的每个套接字并关闭所有套接字.不过要小心.如果在监视线程的线程仍处于活动状态时关闭套接字,则该方法可能会引发异常.在关闭所有套接字之前,您可能应该告诉读取线程退出.并请记住在开始循环之前锁定clients.
*还要确保在使用writers时也将其锁定.

如果您提供了有关您期望应用程序执行的更详细的说明,则可能会获得更多有用的信息.因为这是一个非常广泛的问题和答案,因此跳过了很多内容.如果您有更具体的问题,则可能会得到更具体的答案.

祝你好运:)



All of these principals should be used to rewrite the GetMessages method so that it locks resources that are accessed by multiple threads and exists cooperatively. Also, I think the NetworkStream needs to be Dispose()d of when you''re finished with it.

This now changes a whole bunch of other things in your app:
* before you start the server thread (in the connect button callback) set runServer to true.
* to stop the server thread just set runServer to false and the RunServer method will exit - this should replace the call to Environment.Exit.
* the read threads should likewise be killed by setting a bool to false to tell them to exit, if the client hasn''t already sent the magic string.
* where you were closing the global connection before you should now be looping over every socket in clients and closing all of them. Be careful, though. If you close a socket while the thread that''s monitoring it is still alive then that method will probably throw an exception. Before you close all sockets you should probably tell the read threads to exit. And remember to lock clients before you start looping.
* Be sure to lock writers when using it as well.

If you provide a more detailed explanation of what you''re expecting your app to do you may get more helpful info. As it is this is a very broad question and answer that skims over a lot of stuff. If you have a more specific question you''ll probably get a more specific answer.

Good Luck :)


这篇关于插座连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆