环境: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();
}多线程threadsocket跨线程访问 跨线程传参数

解决方案 »

  1.   

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

  2.   


        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();
            }
        }
      

  3.   

    大致是这样,不过还有很多问题,网络断了得处理,以前取得的GPS数据要不要发,客户端中断后的资源回收。这些你就慢慢了解解决吧。
      

  4.   

    下面方法改下        protected void AddClient(string gpsID, TcpClient client)
            {
                lock (clientList)
                {
                    if (!clientList.ContainsKey(gpsID))
                    {
                        clientList.Add(gpsID, client);
                    }
                }
            }
      

  5.   

    你好。我的需求几乎跟楼主一样,不过代码是这样写的:
    你能帮我也改一下吗?按照楼主的需求就行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();
                }
            }
      

  6.   


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

  7.   

    你抄袭的代码,服务器端接收到一些bytes之后只是打印在debug窗口里而已。假设说设计网络程序需要读100页的资料,那么你只是抄袭了前边3、4页,根本没有理解更多的。设计通讯程序,你需要自己懂得设计信令格式,来解析所收到的bytes的内涵(发送消息是也需要信令格式)。而你抄袭的代码丝毫没有这方面的概念。你还让别人“按照我原帖写的程序 写一下代码”,我想这很难。你问了什么样的问题,决定了你能得到什么样的回答。就好比如说:如果判断说对方没有学过厨师,傻瓜才会跟他讨论做大餐时调料的控制问题。
      

  8.   


    写完善的代码确实很难,不过catchdream朋友加的代码也确实没有实现楼主第三个需求
    估计楼主是最关键的部分不会写吧。
    协议格式倒不用太注意,直接socket.Send(buffer..)传就好了,意思明了就行。
    我只会那种线程独立的,用全局变量,然后1线程传值给2线程的
    楼主这种模式的,我也不会写:)也期待有人能写点大概的代码,学习学习。
     
      

  9.   

    第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);
                        }