【发布时间】:2020-07-03 07:11:29
【问题描述】:
我在与 TCPListeners 和套接字建立聊天连接时遇到了一个奇怪的问题。由于某种原因,当客户端“连接”到服务器时,它会显示他们已经连接了两次。还有什么奇怪的,一旦所有用户都连接了,我会向他们所有人发送一条消息。他们会回复并确认他们的聊天已经开始。
我注意到我的设置方式:
- 根据日志显示,用户“连接”两次,第二次“连接在遇到白色(真)循环时发生。
- 当他们将确认发送回服务器时,并非所有数据都被发送过来。如果我在客户端上执行线程睡眠,它似乎确实开始工作,但仍然不一致。
代码如下:
服务器:
private TcpListener tcpListener;
private Thread listen;
private TcpListener tcpUser1, tcpUser2,tcpUser3;
NetworkStream User1Stream,User2Stream,User3Stream;
public event NetworkMessageStringDelegate MessageFromUser;
TcpClient client;
public void start(string ip){
IpHostEntry host = dns.GetHostEntry(dns.GetHostName());
IpAddress[] ip = host.AddressList;
serverStatus = "Server started with IP of: " + ip;
Thread.Sleep(1);
tcpUser1 = new TcpListener(IpAddress.Any, 4001);
listen = new Thread(new ThreadStart(() => ListenUser1(tcpUser1)));
listen.Start();
Thread.Sleep(1);
tcpUser2 = new TcpListener(IpAddress.Any, 4002);
listen = new Thread(new ThreadStart(() => ListenUser2(tcpUser2)));
listen.Start();
Thread.Sleep(1);
tcpUser3 = new TcpListener(IpAddress.Any, 4003);
listen = new Thread(new ThreadStart(() => ListenUser3(tcpUser3)));
listen.Start();
Thread.Sleep(1);
}
public void ListenUser3(TcpListener tmp){
tcpListener = (TcpListener)tmp;
Socket = "Listening for User3";
tcpUser3.Start();
Thread.Sleep(2);
while(true){
user3 = this.tcpListener.AcceptTcpClient();
Thread user3Thread = new Thread(new ParmeterizedThreadStart(receiveUser3Data));
user3Thread.Start(user3);
}
}
//Mostly from MS documenation
private void receiveUser3Data(object client){
client = (TcpClient)client;
User3Stream = client.getStream();
Socket = "Connected to User: " + client.Client.RemoteEndPoint.toString();
byte[] message = new byte[4096];
int total;
//This is the line it will display the socket message Twice. "Connected to User...."
while(true){
total = 0;
try{
do{
total = User3Stream.Read(message,0,4096);
}
while(user3.DataAvailable);
}
catch()
{
Socket = "Error State";
}
}
byte[] infoPacket = new byte[total];
Array.ConstrainedCopy(message,0,infoPacket,total);
if(MessageFromUser3 != null){
MessageFromUser?.Invoke(packet);
}
}
客户:
public void ConfigureUser3(){
try{
socket = new Network.TCPIPClient();
socket.ReceiveMessage() = new Newowrk.TCPIPClient.NetworkMessageStringDelgate(MessageFromserver);
socket.SendMessage() = new Newowrk.TCPIPClient.NetworkMessageStringDelgate(sendMessage);
userThread = new Thread(() => socket.Start("0.0.0.0),4054));
userThread.Start();
}
catch(Exception ex){
}
}
//This is where if I sleep it will send but it is still inconsident
private void SendMEssageToSever(object tmpVal){
object[] sendMessage = tmpVal as object[];
string tmpSendValue = tmpVal[0].ToString();
byte sendValue = Coonvert.ToByte(tmpVal[1]);
packetData[0] = 0;
packetData[1] = sendValue;
packetData[2] = Convert.ToByte(tmpSendValue);
socket.sendMessage = packetData;
}
private voide sendMessage(byte[] userMessage){
try{
if(socket){
outputMessage.Enqueue(userMessage);
while(outputMessage.Count > 0){
Byte[] sendMessage = outputMessage.Dequeue();
string message = ascII.GetString(sendMessage);
if(socket.Connected){
lock(socket){
socket.Send(sendMessage,sendMessage.length,0);
}
}
}
}
}
catch(Exception ex)
}
对于连接到服务器的所有用户,此代码基本上是重复的。
【问题讨论】:
-
此代码无法编译。为什么要发布无法编译的代码?看看这个:
ParmeterizedThreadStart。看看这个:User3Stream = client.getStream();,客户端的类型也是object。为什么?复制/粘贴代码并在此处更改以使其出错,这不是额外的努力吗? -
TcpListener具有异步方法,例如BeginAcceptTcpClient。TcpClient.GetStream()(这是一个NetworkStream)也有像BeginRead这样的异步方法。我建议您更改代码以使用这些并将用户状态存储在一个类中,并在 Begin* 和 End* 方法之间来回传递该类。这样你就可以支持 N 个用户,而不必为每个用户重复代码。您也不必为 3 个连接使用 3 个不同的侦听器。有一个听众并接受这个听众的客户。其余的是通过TcpClient.GetStream()进行的双向通信 -
@OguzOzgul 你有时间举例说明你的意思吗?猜你的意思类似于:stackoverflow.com/questions/43431196/…
-
我有,如果你能解释一下你的问题中的代码是如何结束的:) 你真的有一个工作源代码吗?
-
是的,我愿意,哈哈。当我把大部分代码放在那里并从 cmets 粘贴时,大部分代码都被注释掉了,因为其他工作代码也不起作用,但这更接近。对此感到抱歉。