多线程多客户端初级问题请教
环境:VS2008 + C#窗体程序情况:1. 一个服务器端程序
2. 多个GPS终端设备
3. 可能多个客户端软件
上面2和3都通过TCP协议连接到服务器端程序,其中2是设备,只发送到服务器端就可以了。3是软件客户端,不但要发送,同时也能接受服务器端发送过来的数据。
服务器端程序永远在接收2的设备发送过来的数据。
现在我要实现这样一种需求:
在3的客户端软件界面上,选择一种GPS设备编号,然后将此编号发送给服务器端程序,服务器端程序接收到3的客户端发送过来的数据后,将实时接收到的该GPS设备数据转发给3的客户端软件
这个该怎么实现?请各位高手帮我实现以下。
下面程序是服务器端接收2和3的两种客户端数据的多线程监听和接收方式(两种客户端发送的协议数据结构一样)。
多线程 thread socket 跨线程访问 跨线程传参数 --------------------编程问答-------------------- 服务器端程序建2个tcp服务端口,比如5000 5001
//服务器为每一个连接客户端产生一个线程,这样接受多个连接:
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();
}
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();
}
}
你好,能帮我按照我原帖写的程序 写一下代码吗? --------------------编程问答-------------------- 大致是这样,不过还有很多问题,网络断了得处理,以前取得的GPS数据要不要发,客户端中断后的资源回收。这些你就慢慢了解解决吧。 --------------------编程问答-------------------- 下面方法改下
--------------------编程问答--------------------
protected void AddClient(string gpsID, TcpClient client)
{
lock (clientList)
{
if (!clientList.ContainsKey(gpsID))
{
clientList.Add(gpsID, client);
}
}
}
你好。我的需求几乎跟楼主一样,不过代码是这样写的:
你能帮我也改一下吗?按照楼主的需求就行
--------------------编程问答--------------------
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();
}
}
这个代码里似乎没有关于我要的东西吧?
我要的需求是
1 GPS设备可以跟服务器通讯
2 客户端软件可以跟服务器通讯
这两个你应该都写了
3 客户端软件界面上如果选择某个GPS设备,则服务器接收到这个GPS设备的数据后转发到客户端软件
这个过程应该是客户端软件发送一个连接请求到服务器(发送GPSID),由于服务器一直在监听(就是一直在接收GPS设备的数据),这个时候比较一下两个GPSID是否相同,如果相同,则将此GPSID对应的数据发给客户端软件
这个第3点你没写吧?我关键是这个不会,如何在线程间转发呢?
--------------------编程问答-------------------- 你抄袭的代码,服务器端接收到一些bytes之后只是打印在debug窗口里而已。
假设说设计网络程序需要读100页的资料,那么你只是抄袭了前边3、4页,根本没有理解更多的。设计通讯程序,你需要自己懂得设计信令格式,来解析所收到的bytes的内涵(发送消息是也需要信令格式)。而你抄袭的代码丝毫没有这方面的概念。你还让别人“按照我原帖写的程序 写一下代码”,我想这很难。
你问了什么样的问题,决定了你能得到什么样的回答。就好比如说:如果判断说对方没有学过厨师,傻瓜才会跟他讨论做大餐时调料的控制问题。 --------------------编程问答--------------------
写完善的代码确实很难,不过catchdream朋友加的代码也确实没有实现楼主第三个需求
估计楼主是最关键的部分不会写吧。
协议格式倒不用太注意,直接socket.Send(buffer..)传就好了,意思明了就行。
我只会那种线程独立的,用全局变量,然后1线程传值给2线程的
楼主这种模式的,我也不会写:)也期待有人能写点大概的代码,学习学习。
--------------------编程问答-------------------- 我来帮顶一下,这个这个多线程的,应该会有很多人都有类似的问题吧 --------------------编程问答-------------------- 哎呀,还是没人解决啊 --------------------编程问答--------------------
第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#