不要意思,篇幅有点长,希望大家耐心地看。大家好,我的情况是这样的:局域网内,经过路由器,3个客户端Socket连接服务器(其中一台作为服务器),发一个请求(通过ComboBox更换请求的类型),服务器根据请求,死循环的发送相应的结果到客户端,频率是500ms / 次。工作模式:说明:
1.服务器启动。
2.服务器启动8个线程(由主线程启动,分别不断地从数据库读取数据)。
3.开始监听,并开辟一个线程等待客户端连接。
4.客户端连接上之后,服务器开一个线程接受他的命令。
5.服务器根据请求,取8个线程中的一个所产生的结果,再开一个线程,用作死循环返回给客户。如果客户第一次请求“水果”,然后服务器死循环发送“苹果,蕉”,然后客户第二次请求“海鲜”,服务器先销毁之前的线程,再取得“海鲜”的数据死循环发送“虾,蟹”。发送的频率是500ms / 次。
疑问:
1.服务器的设计,合理吗?
2.象这样开启多级的线程,会出什么问题吗?除了那8个线程是由主线程开出来之外,其他线程都是有副线程开出来的,会不会有什么问题?
3.客户多的时候,这样设计还能行吗?
出现的问题:
1.当客户端请求“海鲜”,接收到的是“虾、蟹”,当他切换到“水果”,接收到的还是“虾、蟹”,要经过几秒甚至十几秒才能收到“苹果、蕉”,这个“延时”时快时慢。以下是代码//8个线程:
/// <summary>
/// 启动服务器
public MyServer StartupServer(string serverIP, string serverPort)
{
myServer = MyServer.getInstance(serverIP, Convert.ToInt32(serverPort)); InitDataTable(ref initedDT, listCompanys); myServer.Listen(); // 第一个线程
Thread thGetSeaFood = new Thread(new ThreadStart(GetSeaFood));
thGetSeaFood .IsBackground = true;
thGetSeaFood .Start(); // 依次类推 return myServer;
}private void GetSeaFood()
{
List<DataTable> ldt = null; DataTable dt2 = null; DataTable dt = null; while (true)
{
ldt = new List<DataTable>(); dt2 = initedDT.Clone(); dt = // 读数据库 dtResult = dt2; Thread.Sleep(500); }
}//服务器监听:
/// 开始监听,并开一个线程,等待客户端连接
public void Listen()
{
myServer.Listener = new TcpListener(IPAddress.Parse(myServer.ServerIP), myServer.ServerPort);
myServer.Listener.Start(); BeginWaitingConnection();
}
//等待客户端连接:
/// 开一个线程,等待客户端连接
private void BeginWaitingConnection()
{
this.thWaitingConnect = new Thread(new ThreadStart(WaitingConnection));
this.thWaitingConnect.IsBackground = true;
this.thWaitingConnect.Start();
}/// 等待客户端连接
private void WaitingConnection()
{
while (true)
{
Socket socket = myServer.Listener.AcceptSocket(); if (null != socket)
{
MyClient myClient = new MyClient();
myClient.SClient = socket;
myClient.ClientIp = Regex.Split(myClient.SClient.RemoteEndPoint.ToString(), ":")[0]; myClient.ThReceiveCmd = new Thread(new ParameterizedThreadStart(ReceiveCmd));
myClient.ThReceiveCmd.IsBackground = true;
myClient.ThReceiveCmd.Start(myClient); }
}
}
//处理请求:
/// 分析命令
private void AnalyseCmd(MyClient myClient, string cmd)
{
string[] param = Tool.GetParms(cmd); // 接收到客户端请求
switch (param[0])
{
case CmdCollection.SM1_CMD_REQUEST_FOR_DATA:
{
string userName = param[1];
string type = param[2]; //类型 if (null != eventPrepareResponseWaterData)
{
// 如果是第二次请求(客户端切换请求类型),就要把之前的死循环返回结果的线程销毁掉
DestoryClientThread(userName); dicClients[userName].ThSendCmd = new Thread(new ParameterizedThreadStar(PrepareToSendData));
dicClients[userName].ThSendCmd.IsBackground = true;
dicClients[userName].ThSendCmd.Start(new object[] { myClient, type});
} break;
}
}
}
/// 销毁客户端线程
private void DestoryClientThread(string userName)
{
if (dicClients.ContainsKey(userName))
{
if (null != dicClients[userName].ThSendCmd)
{
dicClients[userName].ThSendCmd.Abort();
//dicClients[userName].ThSendCmd.Join();
}
}
}
//返回结果:
private void PrepareToSendData(object sendParam)
{
object[] temp = (sendParam as object[]);
MyClient myClient = temp[0] as MyClient;
string type = temp[1].ToString();
DataTable dtResponseData = null; do
{ dtResponseData = eventPrepareResponseWaterData(type); //服务器根据请求,取得结果 SendToClient(myClient, CmdCollection.SM1_CMD_RESPONSE_WATER_TO_CLIENT, dtResponseData, type); if (Thread.CurrentThread.ThreadState == ThreadState.Background)
{
Thread.Sleep(500);
} dtResponseData = null; }
while (true);
}
private void SendToClient(MyClient myClient, string cmd, DataTable dtWater, string type)
{
if (dicClients.ContainsKey(myClient.UserName))
{
Socket sClient = dicClients[myClient.UserName].SClient; if (null != dtWater && sClient.Connected && Thread.CurrentThread.ThreadState == ThreadState.Background)
{
myClient.Sw = new StreamWriter(new NetworkStream(sClient));
} if (null != dtWater && sClient.Connected && Thread.CurrentThread.ThreadState == ThreadState.Background)
{
myClient.Sw.WriteLine(String.Format("{0}|{1}|{2}\r\n\t\t\t", cmd, Tool.SerializeAndCompress(dtWater), type));
} if (null != dtWater && sClient.Connected && Thread.CurrentThread.ThreadState == ThreadState.Background)
{
myClient.Sw.Flush();
} }}
疑问:
1.服务器的设计,合理吗?
2.象这样开启多级的线程,会出什么问题吗?除了那8个线程是由主线程开出来之外,其他线程都是有副线程开出来的,会不会有什么问题?
3.客户多的时候,这样设计还能行吗?
出现的问题:
1.当客户端请求“海鲜”,接收到的是“虾、蟹”,当他切换到“水果”,接收到的还是“虾、蟹”,要经过几秒甚至十几秒才能收到“苹果、蕉”,这个“延时”时快时慢。
请大家指教,先谢谢了!
1.服务器启动。
2.服务器启动8个线程(由主线程启动,分别不断地从数据库读取数据)。
3.开始监听,并开辟一个线程等待客户端连接。
4.客户端连接上之后,服务器开一个线程接受他的命令。
5.服务器根据请求,取8个线程中的一个所产生的结果,再开一个线程,用作死循环返回给客户。如果客户第一次请求“水果”,然后服务器死循环发送“苹果,蕉”,然后客户第二次请求“海鲜”,服务器先销毁之前的线程,再取得“海鲜”的数据死循环发送“虾,蟹”。发送的频率是500ms / 次。
疑问:
1.服务器的设计,合理吗?
2.象这样开启多级的线程,会出什么问题吗?除了那8个线程是由主线程开出来之外,其他线程都是有副线程开出来的,会不会有什么问题?
3.客户多的时候,这样设计还能行吗?
出现的问题:
1.当客户端请求“海鲜”,接收到的是“虾、蟹”,当他切换到“水果”,接收到的还是“虾、蟹”,要经过几秒甚至十几秒才能收到“苹果、蕉”,这个“延时”时快时慢。以下是代码//8个线程:
/// <summary>
/// 启动服务器
public MyServer StartupServer(string serverIP, string serverPort)
{
myServer = MyServer.getInstance(serverIP, Convert.ToInt32(serverPort)); InitDataTable(ref initedDT, listCompanys); myServer.Listen(); // 第一个线程
Thread thGetSeaFood = new Thread(new ThreadStart(GetSeaFood));
thGetSeaFood .IsBackground = true;
thGetSeaFood .Start(); // 依次类推 return myServer;
}private void GetSeaFood()
{
List<DataTable> ldt = null; DataTable dt2 = null; DataTable dt = null; while (true)
{
ldt = new List<DataTable>(); dt2 = initedDT.Clone(); dt = // 读数据库 dtResult = dt2; Thread.Sleep(500); }
}//服务器监听:
/// 开始监听,并开一个线程,等待客户端连接
public void Listen()
{
myServer.Listener = new TcpListener(IPAddress.Parse(myServer.ServerIP), myServer.ServerPort);
myServer.Listener.Start(); BeginWaitingConnection();
}
//等待客户端连接:
/// 开一个线程,等待客户端连接
private void BeginWaitingConnection()
{
this.thWaitingConnect = new Thread(new ThreadStart(WaitingConnection));
this.thWaitingConnect.IsBackground = true;
this.thWaitingConnect.Start();
}/// 等待客户端连接
private void WaitingConnection()
{
while (true)
{
Socket socket = myServer.Listener.AcceptSocket(); if (null != socket)
{
MyClient myClient = new MyClient();
myClient.SClient = socket;
myClient.ClientIp = Regex.Split(myClient.SClient.RemoteEndPoint.ToString(), ":")[0]; myClient.ThReceiveCmd = new Thread(new ParameterizedThreadStart(ReceiveCmd));
myClient.ThReceiveCmd.IsBackground = true;
myClient.ThReceiveCmd.Start(myClient); }
}
}
//处理请求:
/// 分析命令
private void AnalyseCmd(MyClient myClient, string cmd)
{
string[] param = Tool.GetParms(cmd); // 接收到客户端请求
switch (param[0])
{
case CmdCollection.SM1_CMD_REQUEST_FOR_DATA:
{
string userName = param[1];
string type = param[2]; //类型 if (null != eventPrepareResponseWaterData)
{
// 如果是第二次请求(客户端切换请求类型),就要把之前的死循环返回结果的线程销毁掉
DestoryClientThread(userName); dicClients[userName].ThSendCmd = new Thread(new ParameterizedThreadStar(PrepareToSendData));
dicClients[userName].ThSendCmd.IsBackground = true;
dicClients[userName].ThSendCmd.Start(new object[] { myClient, type});
} break;
}
}
}
/// 销毁客户端线程
private void DestoryClientThread(string userName)
{
if (dicClients.ContainsKey(userName))
{
if (null != dicClients[userName].ThSendCmd)
{
dicClients[userName].ThSendCmd.Abort();
//dicClients[userName].ThSendCmd.Join();
}
}
}
//返回结果:
private void PrepareToSendData(object sendParam)
{
object[] temp = (sendParam as object[]);
MyClient myClient = temp[0] as MyClient;
string type = temp[1].ToString();
DataTable dtResponseData = null; do
{ dtResponseData = eventPrepareResponseWaterData(type); //服务器根据请求,取得结果 SendToClient(myClient, CmdCollection.SM1_CMD_RESPONSE_WATER_TO_CLIENT, dtResponseData, type); if (Thread.CurrentThread.ThreadState == ThreadState.Background)
{
Thread.Sleep(500);
} dtResponseData = null; }
while (true);
}
private void SendToClient(MyClient myClient, string cmd, DataTable dtWater, string type)
{
if (dicClients.ContainsKey(myClient.UserName))
{
Socket sClient = dicClients[myClient.UserName].SClient; if (null != dtWater && sClient.Connected && Thread.CurrentThread.ThreadState == ThreadState.Background)
{
myClient.Sw = new StreamWriter(new NetworkStream(sClient));
} if (null != dtWater && sClient.Connected && Thread.CurrentThread.ThreadState == ThreadState.Background)
{
myClient.Sw.WriteLine(String.Format("{0}|{1}|{2}\r\n\t\t\t", cmd, Tool.SerializeAndCompress(dtWater), type));
} if (null != dtWater && sClient.Connected && Thread.CurrentThread.ThreadState == ThreadState.Background)
{
myClient.Sw.Flush();
} }}
疑问:
1.服务器的设计,合理吗?
2.象这样开启多级的线程,会出什么问题吗?除了那8个线程是由主线程开出来之外,其他线程都是有副线程开出来的,会不会有什么问题?
3.客户多的时候,这样设计还能行吗?
出现的问题:
1.当客户端请求“海鲜”,接收到的是“虾、蟹”,当他切换到“水果”,接收到的还是“虾、蟹”,要经过几秒甚至十几秒才能收到“苹果、蕉”,这个“延时”时快时慢。
请大家指教,先谢谢了!
当时,这中间的命令 协议你自己定下就可以了!
数据量是20K, 压缩有变成5K, 数据量是不大的, 但我是很频繁的, 500ms / 次 .
如果客户多, 每个客户都直接取的话, 服务器就做了许多重复的操作, 就很占CPU.
我感觉一个客户端你开一个线程,用一个TCP链接就可以了啊可以解释一下这句话吗?
我没用TcpClient, 只用Socket.
有客户连接的时候, 服务器都开2个线程用于接受和发送, 这是不是也达到了"交互"的效果?
的确,你的是可以算异步了,不过不是用的BeginXXX方法,你自己新开线程没有使用BeginXXX好,因为你得维护线程的关闭。另外你说的全局变量会相互覆盖的问题,那你就用对象吧,给每个建立的链接分配一个对象,对象内部存放那个判断关键字。我之所以建议你用BeginXXX方法,也是有道理的,你看下MSDN上的示例就会发现,他会传递一个StateObject对象,这个StateObject是自定义的,里面不但可以保存Socket,还可以保持各种信息。我们来看一下BeginSend的函数定义:
public IAsyncResult BeginSend(
byte[] buffer,
int offset,
int size,
SocketFlags socketFlags,
AsyncCallback callback,
Object state
)
这里面最后一个参数用来传递自定义状态对象,这样你就可以把同一个对象传递给BeginSend和BeginReceive函数同时使用了,操作对象中的关键字,一个线程写,一个线程读,这样不是非常完美吗?
当客户A连接后,你可以记录A的Ip在list中和networktream这里面可能记录了很多网络信息。
发送的时候,只要ip对应上,networkstream就可以用来发送信息,这样就不会乱了
我用了dicClients(Dictionary)来存的, 给每个客户端发的信息也没乱.
现在的问题是切换类型, 好慢!!
{
switch (clientType)
{
case "海鲜":
return dtSeadFood.Copy();
case "水果":
return dtFruit.Copy();
// 依次类推
default:
return null;
}
}
而上面的dtSeadFood, 是下面的方法里得出来的private void GetSeaFood()
{
List<DataTable> ldt = null; DataTable dt2 = null; // 这个dt2是表结构 DataTable dt = null; while (true)
{
ldt = new List<DataTable>(); dt2 = initedDT.Clone(); dt = // 读数据库 dtSeadFood= dt2; Thread.Sleep(500);
}
}
如果第一次请求"水果", 服务器返回"香蕉". 然后我切换到"海鲜", 客户端收到的仍然是"香蕉", 要过几秒甚至十几秒才收到"虾".现在还有一种情况是:
如果客户端挂在那里半小时不动, 他切换就慢. 但这个时候不停的切换, 他就快起来了. 这大概是什么问题???
问题解决了.是我某个地方用了Thread.Sleep(); 造成阻塞, 并且累计了.总之...谢谢大家!