我对这个问答方式有点新意,如果我犯了任何错误,请告诉我。我有这个服务器程序,在我的笔记本电脑上运行。服务器是一个控制台应用程序;
class Program
{
static void Main(string[] args)
{
Server sv = new Server("192.168.2.69", 52025);
sv.OnClientAccept += new ClientAcceptHandler(sv_OnClientAccept);
sv.OnClientMessage += new ClientMessageHandler(sv_OnClientMessage);
sv.Start();
}
static void sv_OnClientMessage(Server s, System.Net.Sockets.TcpClient client, string message)
{
Console.WriteLine("Message received from client " + GetClientIp(client) + ": \"" + message + "\"");
string msgToAll = message;
s.SendToAllClients(msgToAll);
Console.WriteLine("Message sent: \"" + message + "\" to the clients:");
foreach (TcpClient cl in s.Clients)
{
Console.WriteLine(GetClientIp(cl));
}
}
static void sv_OnClientAccept(Server s, System.Net.Sockets.TcpClient client)
{
Console.WriteLine("Client Accepted : " + GetClientIp(client));
}
static string GetClientIp(TcpClient Client)
{
return ((IPEndPoint)Client.Client.RemoteEndPoint).Address.ToString();
}
}
服务器类;
public delegate void ClientAcceptHandler(Server s, TcpClient client);
public delegate void ClientMessageHandler(Server s, TcpClient client, string message);
public class Server
{
private List<TcpClient> clients = new List<TcpClient>();
object lockObjc;
private TcpListener server;
private string ip;
private int port;
private Thread accepter, listener;
public List<TcpClient> Clients { get { return this.clients; } set { this.clients = value; } }
public event ClientAcceptHandler OnClientAccept;
public event ClientMessageHandler OnClientMessage;
public Server(string IP, int Port)
{
ip = IP;
port = Port;
}
private void ClientAccepted(TcpClient Client)
{
if (OnClientAccept != null)
{
OnClientAccept.Invoke(this, Client);
}
}
private void ClientMessaged(TcpClient Client, string Message)
{
if (OnClientMessage != null)
{
OnClientMessage.Invoke(this, Client, Message);
}
}
public void Start()
{
lockObjc = new object();
IPAddress ipAddress = IPAddress.Parse(ip);//127.0.0.1 -> local || "192.168.2.69" -> laptop
server = new TcpListener(ipAddress, port);//2014 -> local || 52025
server.Start();
accepter = new Thread(AcceptClients);
accepter.Start();
listener = new Thread(Listen);
listener.Start();
}
private void AcceptClients()
{
while (true)
{
TcpClient attachedCl = server.AcceptTcpClient();
if (attachedCl != null)
{
lock (lockObjc)
{
if (!clients.Contains(attachedCl))
{
clients.Add(attachedCl);
ClientAccepted(attachedCl);
}
}
}
}
}
private void Listen()
{
while (true)
{
for (int i = 0; i < clients.Count; i++)
{
TcpClient client = clients[i];
lock (lockObjc)
{
try
{
StreamReader clientIn = new StreamReader(client.GetStream());
string msg = clientIn.ReadLine();
if (msg != string.Empty)
{
ClientMessaged(client, msg);
}
}
catch
{
}
}
}
}
}
private bool send(TcpClient Client, string Msg)
{
bool b = true;
try
{
TcpClient client = Client;
StreamWriter clientOut = new StreamWriter(client.GetStream());
clientOut.AutoFlush = true;
clientOut.WriteLine(Msg);
}
catch
{
b = false;
}
return b;
}
public bool SendToACLient(TcpClient Client, string Message)
{
return send(Client, Message);
}
public bool SendToAClient(int i, string Message)
{
return send(clients[i], Message);
}
public bool SendToAllClients(string Message)
{
bool b = true;
for (int i = 0; i < clients.Count; i++)
{
b = b && send(clients[i], Message);
}
return b;
}
public bool SendToAllClientsExcept(TcpClient Client, string Message)
{
int x = clients.IndexOf(Client);
bool b = true;
for (int i = 0; i < clients.Count; i++)
{
if (i != x)
{
b = b && send(clients[i], Message);
}
}
return b;
}
}
由于我对服务器 - 客户端关系不熟悉,我不知道服务器部分是否正常,但对我来说似乎可以编程(但我也是业余程序员,没有真正的教育)。
客户端部分是;
public delegate void ServerMessageHandler(Client Receiver, string Message);
public class Client
{
private StreamReader clientIn;
private StreamWriter clientOut;
private TcpClient client;
private Thread listener;
private object lockObj;
public event ServerMessageHandler OnServerMessage;
public bool Connected { get { return (client != null && client.Connected); } }
public Client()
{
lockObj = new object();
client = new TcpClient();
listener = new Thread(Listen);
}
private void ServerMessaged(string Message)
{
if (OnServerMessage != null)
{
OnServerMessage.Invoke(this, Message);
}
}
private void Listen()
{
string serverMsg;
while (true)
{
try
{
serverMsg = clientIn.ReadLine();
if (serverMsg != string.Empty)
{
ServerMessaged(serverMsg);
}
}
catch
{
}
}
}
private void start()
{
listener.Start();
}
public bool Connect(string Ip, int Port)
{
client.Connect(Ip, Port);//"192.168.2.69", 52025
if (client.Connected)
{
clientIn = new StreamReader(client.GetStream());
clientOut = new StreamWriter(client.GetStream());
clientOut.AutoFlush = true;
start();
}
return client.Connected;
}
public void Send(string Message)
{
if (client.Connected)
{
clientOut.WriteLine(Message);
}
}
}
这是我运行Client类的表单;
public partial class Form1 : Form
{
string s;
Client c;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
c = new Client();
c.OnServerMessage += new ServerMessageHandler(c_OnServerMessage);
bool b = c.Connect("192.168.2.69", 52025);
if (b)
{
s += "Connected to the server: 192.168.2.69:52025\r\n";
}
timer1.Start();
}
void c_OnServerMessage(Client Receiver, string Message)
{
s += "Server: " + Message + "\r\n";
}
private void button1_Click(object sender, EventArgs e)
{
c.Send(textBox1.Text);
}
private void timer1_Tick(object sender, EventArgs e)
{
textBox2.Text = s;
}
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
c.Send(textBox1.Text);
}
}
}
此表单有两个文本框,第一个是用户输入的文本框(textBox1
),第二个是显示服务器响应的文本框。为什么我没有使用Console
?因为我试过这种方式,我正在等待来自用户(Console.ReadLine
)的输入,据我所知,锁定控制台直到用户按下输入,即使很难我使用线程来监听服务器,我无法在控制台上显示服务器答案。
所以,我决定创建自己的控制台(排序)。我运行计时器来显示消息的原因是当我尝试从线程调用的方法更改文本框文本时遇到错误(这是c_OnServerMessage
方法,被间接调用,来自来自Client类的监听器线程)
但我得到的问题是:我在笔记本电脑上运行服务器,我还在笔记本电脑上运行一个客户端,这完全正常,直到我在另一台计算机上打开另一个客户端。事情就是这样:我从客户端发送消息,消息到达服务器并被发回。当我发送另一条消息时,该消息直到我从客户端2发送消息才到达服务器。当我从客户端2发送消息时,服务器从客户端2获取消息甚至很难我首先从客户端1发送消息。
所以基本上发生的事情是,如果我运行2个客户端,我不能从客户端连续发送2条消息,它有点像国际象棋游戏,其中有转向播放。我真的不明白原因。
这个问题可能来自一个基本的错误,但我必须写下这整条信息才能表达自己。感谢您的耐心和帮助。
编辑: 问题解决了,原因是:TCP server with multiple Clients 我的问题是来自Server类的Listen方法。 Listen方法由一个线程调用,但它本身仍然运行for循环。如果循环停止并等待某些东西,线程将没有任何区别。再次感谢,我想我会继续提问,因为我不知道解决问题会发生什么。