当前位置:编程学习 > C#/ASP.NET >>

多线程多客户端初级问题请教

环境:VS2008 + C#窗体程序
情况:1. 一个服务器端程序
      2. 多个GPS终端设备
      3. 可能多个客户端软件
上面2和3都通过TCP协议连接到服务器端程序,其中2是设备,只发送到服务器端就可以了。3是软件客户端,不但要发送,同时也能接受服务器端发送过来的数据。
服务器端程序永远在接收2的设备发送过来的数据。
现在我要实现这样一种需求:
在3的客户端软件界面上,选择一种GPS设备编号,然后将此编号发送给服务器端程序,服务器端程序接收到3的客户端发送过来的数据后,将实时接收到的该GPS设备数据转发给3的客户端软件

这个该怎么实现?请各位高手帮我实现以下。


下面程序是服务器端接收2和3的两种客户端数据的多线程监听和接收方式(两种客户端发送的协议数据结构一样)。

//服务器为每一个连接客户端产生一个线程,这样接受多个连接:
private TcpListener tcpListener;
private Thread listenThread;

public Server()
{
    this.tcpListener = new TcpListener(IPAddress.Any, 3000);
    this.listenThread = new Thread(new ThreadStart(ListenForClients));
    this.listenThread.Start();
}

private void ListenForClients()
{
    this.tcpListener.Start();
    while (true)
    {
        //blocks until a client has connected to the server
        TcpClient client = this.tcpListener.AcceptTcpClient();

        //create a thread to handle communication
        //with connected client
        Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
        clientThread.Start(client);
    }
}

private void HandleClientComm(object client)
{
    TcpClient tcpClient = (TcpClient)client;
    NetworkStream clientStream = tcpClient.GetStream();

    byte[] message = new byte[4096];
    int bytesRead;

    while (true)
    {
        bytesRead = 0;
        try
        {
            //blocks until a client sends a message
            bytesRead = clientStream.Read(message, 0, 4096);
        }
        catch
        {
            //a socket error has occured
            break;
        }

        if (bytesRead == 0)
        {
            //the client has disconnected from the server
            break;
        }

        //message has successfully been received
        ASCIIEncoding encoder = new ASCIIEncoding();
        System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
    }
    tcpClient.Close();
}

多线程 thread socket 跨线程访问 跨线程传参数 --------------------编程问答-------------------- 服务器端程序建2个tcp服务端口,比如5000  5001
5000用于处理接收多个gps设备的协议数据,5001用于接收发送数据给多个客户端(自己定义数据协议).
例TcpClienta[100]是gps设备连接过来的,TcpClientb[100]是客户端连接;
  TcpClienta[x]收到gps数据后可以通过TcpClientb[y]发给客户端,当然要判断2个连接上的设备ID一致. --------------------编程问答--------------------

    public class Server
    {
        //服务器为每一个连接客户端产生一个线程,这样接受多个连接:
        private TcpListener tcpListener;
        private Thread listenThread;
        private SortedList<string, TcpClient> clientList;        

        public Server()
        {
            this.clientList = new SortedList<string, TcpClient>();
            this.tcpListener = new TcpListener(IPAddress.Any, 3000);
            this.listenThread = new Thread(new ThreadStart(ListenForClients));
            this.listenThread.Start();
        }

        protected void AddClient(string gpsID, TcpClient client)
        {
            lock (clientList)
            {
                clientList.Add(gpsID, client);
            }
        }

        protected TcpClient GetClient(string gpsID)
        {
            TcpClient client = null;
            lock (clientList)
            {
                if (clientList.ContainsKey(gpsID))
                {
                    client = clientList[gpsID];
                }
            }
            return client;
        }

        private void ListenForClients()
        {
            this.tcpListener.Start();
            while (true)
            {
                //blocks until a client has connected to the server
                TcpClient client = this.tcpListener.AcceptTcpClient();
                
                //create a thread to handle communication
                //with connected client
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                clientThread.Start(client);
            }
        }

        private void HandleClientComm(object client)
        {
            TcpClient tcpClient = (TcpClient)client;
            NetworkStream clientStream = tcpClient.GetStream();

            byte[] message = new byte[4096];
            int bytesRead;
            string gpsID = "";

            while (true)
            {
                bytesRead = 0;
                try
                {
                    //blocks until a client sends a message
                    bytesRead = clientStream.Read(message, 0, 4096);
                    //TBD: if Client, Get GPSID
                    gpsID = "";
                    AddClient(gpsID, tcpClient);
                    //TBD: if GPS, GetGPSData
                    byte[] gpsData = null;
                    string currentGPSID = "";
                    TcpClient tcpClientByGPS = GetClient(currentGPSID);
                    if (tcpClientByGPS != null)
                    {
                        tcpClientByGPS.GetStream().BeginWrite(gpsData, 0, gpsData.Length, null, null);
                    }
                }
                catch
                {
                    //a socket error has occured
                    break;
                }

                if (bytesRead == 0)
                {
                    //the client has disconnected from the server
                    break;
                }

                //message has successfully been received
                ASCIIEncoding encoder = new ASCIIEncoding();
                System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
            }
            tcpClient.Close();
        }
    }
--------------------编程问答--------------------
引用 1 楼 zdbb 的回复:
服务器端程序建2个tcp服务端口,比如5000  5001
5000用于处理接收多个gps设备的协议数据,5001用于接收发送数据给多个客户端(自己定义数据协议).
例TcpClienta[100]是gps设备连接过来的,TcpClientb[100]是客户端连接;
  TcpClienta[x]收到gps数据后可以通过TcpClientb[y]发给客户端,当然要判……


你好,能帮我按照我原帖写的程序 写一下代码吗? --------------------编程问答-------------------- 大致是这样,不过还有很多问题,网络断了得处理,以前取得的GPS数据要不要发,客户端中断后的资源回收。这些你就慢慢了解解决吧。 --------------------编程问答-------------------- 下面方法改下

        protected void AddClient(string gpsID, TcpClient client)
        {
            lock (clientList)
            {
                if (!clientList.ContainsKey(gpsID))
                {
                    clientList.Add(gpsID, client);
                }
            }
        }
--------------------编程问答--------------------
引用 5 楼 catchdream 的回复:
下面方法改下
C# code?12345678910        protected void AddClient(string gpsID, TcpClient client)        {            lock (clientList)            {                if (!clientList.ContainsKey(g……



你好。我的需求几乎跟楼主一样,不过代码是这样写的:
你能帮我也改一下吗?按照楼主的需求就行

private void ServerForm_Load(object sender, EventArgs e)
        {
            //测试线程
            Thread SoceketTestThread = new Thread(new ThreadStart(StartListening));
            SoceketTestThread.Start();
                            
            //实例化
            Set_Text = new set_Text(set_ListViewCarFlowText); 
        }
 
        /// <summary>
        /// 开启端口监听线程
        /// </summary>
        private void StartListening()
        {
            listener = new TcpListener(IPAddress.Parse(m_serverIP), int.Parse(m_serverPort));
            listener.Start();
            while (StartListeningFlg)
            {
                try
                {
                    //一旦在该端口号监听到信息,则启动一个新的线程
                    Socket s = listener.AcceptSocket();
                    //判断是否处在连接状态中
                    if (s.Connected == true)
                    {
                        clientsocket = s;
                        clientservice = new Thread(new ThreadStart(ServiceClient));
                        clientservice.Start();
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.ToString());
                    return;
                }
            }
            //停止监听
            listener.Stop();
        }
 
        /// <summary>
        /// 开启对客户端信息的接收处理线程
        /// </summary>
        private void ServiceClient()
        {
            try
            {
                while (ServiceClientFlg)
                {
                    Byte[] buffer = new Byte[1024];
 
                    //设置该socket为阻止模式
                    clientsocket.Blocking = true;
                    //获取客户端IP地址
                    IPEndPoint ipe = (IPEndPoint)clientsocket.RemoteEndPoint;
   
                    //接收二进制byte数据
                    int intRec = clientsocket.Receive(buffer);
                    if (intRec < 1)
                    {
                        clientsocket.Close();
                        //委托相关,用以该线程操控主线程上的控件
                        listViewCarFlow.Invoke(Set_Text, new object[] { "\r\n" + "已经断开连接" });
                        break;
                    }
 
                    //将二进制数据信息转换成字符串型
                    string strReceiveMessage = System.Text.Encoding.ASCII.GetString(buffer);
        
                    //委托相关,用以该线程操控主线程上的控件
                    listViewCarFlow.Invoke(Set_Text, new object[] { "\r\n" + strReceiveMessage });
 
                    //发送到客户端
                    byte[] bs = Encoding.ASCII.GetBytes("i have recevied from" + strIP);
                    clientsocket.Send(bs, bs.Length, 0);
                }
            }
            catch (Exception ex)
            {
                clientsocket.Close();
            }
        }

--------------------编程问答--------------------
引用 2 楼 catchdream 的回复:
C# code?12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394……


这个代码里似乎没有关于我要的东西吧?
我要的需求是
1 GPS设备可以跟服务器通讯
2 客户端软件可以跟服务器通讯
这两个你应该都写了
3 客户端软件界面上如果选择某个GPS设备,则服务器接收到这个GPS设备的数据后转发到客户端软件
  这个过程应该是客户端软件发送一个连接请求到服务器(发送GPSID),由于服务器一直在监听(就是一直在接收GPS设备的数据),这个时候比较一下两个GPSID是否相同,如果相同,则将此GPSID对应的数据发给客户端软件
  这个第3点你没写吧?我关键是这个不会,如何在线程间转发呢?

--------------------编程问答-------------------- 你抄袭的代码,服务器端接收到一些bytes之后只是打印在debug窗口里而已。

假设说设计网络程序需要读100页的资料,那么你只是抄袭了前边3、4页,根本没有理解更多的。设计通讯程序,你需要自己懂得设计信令格式,来解析所收到的bytes的内涵(发送消息是也需要信令格式)。而你抄袭的代码丝毫没有这方面的概念。你还让别人“按照我原帖写的程序 写一下代码”,我想这很难。

你问了什么样的问题,决定了你能得到什么样的回答。就好比如说:如果判断说对方没有学过厨师,傻瓜才会跟他讨论做大餐时调料的控制问题。 --------------------编程问答--------------------
引用 8 楼 sp1234 的回复:
你抄袭的代码,服务器端接收到一些bytes之后只是打印在debug窗口里而已。

假设说设计网络程序需要读100页的资料,那么你只是抄袭了前边3、4页,根本没有理解更多的。设计通讯程序,你需要自己懂得设计信令格式,来解析所收到的bytes的内涵(发送消息是也需要信令格式)。而你抄袭的代码丝毫没有这方面的概念。你还让别人“按照我原帖写的程序 写一下代码”,我想这很难。
……


写完善的代码确实很难,不过catchdream朋友加的代码也确实没有实现楼主第三个需求
估计楼主是最关键的部分不会写吧。
协议格式倒不用太注意,直接socket.Send(buffer..)传就好了,意思明了就行。
我只会那种线程独立的,用全局变量,然后1线程传值给2线程的
楼主这种模式的,我也不会写:)也期待有人能写点大概的代码,学习学习。
  --------------------编程问答-------------------- 我来帮顶一下,这个这个多线程的,应该会有很多人都有类似的问题吧 --------------------编程问答-------------------- 哎呀,还是没人解决啊 --------------------编程问答--------------------
引用 7 楼 yyjt2013 的回复:
引用 2 楼 catchdream 的回复:C# code?1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283……

第3点最重要是怎么2端的对应关系,所以我帖子里有2个TBD,由你自己补充完整。不过基本的思路是,如果是客户端连进来,(假设有GPSID 作为GPS与Client的联系关键),那么把Client存储进列表;而如果是GPS端连进来,则查找Client列表,得到对应的Client,然后把从GPS取得的数据转发就行。
基本就是补充下面代码的TBD:

                    //blocks until a client sends a message
                    bytesRead = clientStream.Read(message, 0, 4096);
                    //TBD: if Client, Get GPSID
                    gpsID = "";
                    AddClient(gpsID, tcpClient);
                    //TBD: if GPS, GetGPSData
                    byte[] gpsData = null;
                    string currentGPSID = "";
                    TcpClient tcpClientByGPS = GetClient(currentGPSID);
                    if (tcpClientByGPS != null)
                    {
                        tcpClientByGPS.GetStream().BeginWrite(gpsData, 0, gpsData.Length, null, null);
                    }
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,