我正在寻找一种在TCP中实现协议来发送和接收简单字符串消息的方法。我有一个客户端和一个服务器应用程序,当我们第一次开始运行时,我按下客户端上的连接按钮连接到服务器。在服务器的列表框中弹出一些文本,表明客户端已连接,并且在客户端的列表框中会出现一些文本,表明它已连接到服务器。
那部分工作正常,但现在我希望能够将其他字符串发送到服务器,并且根据我发送的字符串会使服务器执行某个操作,我该怎么做?想到的第一个想法是在某处使用if-then语句。我将在下面发布我的代码:
服务器:
private static int port = 8080;
private static TcpListener listener;
private static Thread thread;
private void Form1_Load(object sender, EventArgs e)
{
listener = new TcpListener(new IPAddress(new byte[] { 10, 1, 6, 130 }), port);
thread = new Thread(new ThreadStart(Listen));
thread.Start();
}
private void Listen()
{
listener.Start();
listBox1.Invoke(new EventHandler(delegate { listBox1.Items.Add("Listening on: " + port.ToString()); }));
while (true)
{
listBox1.Invoke(new EventHandler(delegate { listBox1.Items.Add("Waiting for connection...."); }));
TcpClient client = listener.AcceptTcpClient();
Thread listenThread = new Thread(new ParameterizedThreadStart(ListenThread));
listenThread.Start(client);
}
}
//client thread
private void ListenThread(Object client)
{
NetworkStream netstream = ((TcpClient)client).GetStream();
listBox1.Invoke(new EventHandler(delegate { listBox1.Items.Add("Request made"); }));
byte[] resMessage = Encoding.ASCII.GetBytes("Connected to Server");
netstream.Write(resMessage, 0, resMessage.Length);
netstream.Flush();
}
客户端:
TcpClient tcpclnt;
private void buttonConnect_Click(object sender, EventArgs e)
{
try
{
tcpclnt = new TcpClient();
userEventBox.Items.Add("Connecting.....");
try
{
tcpclnt.Connect("10.1.6.130", 8080);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return;
}
Stream stm = tcpclnt.GetStream();
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
string returndata = System.Text.Encoding.ASCII.GetString(bb);
userEventBox.Items.Add(returndata);
tabControl1.Enabled = true;
//need a way for the server see this string
string populateList = "Test";
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(populateList);
stm.Write(ba, 0, ba.Length);
}
catch (Exception ex)
{
Console.WriteLine("Error..... " + ex.StackTrace);
}
}
我很困惑,非常感谢您就此主题提供的任何帮助。谢谢。
来源 - > C# client-server protocol/model question
答案 0 :(得分:4)
建立连接后,客户端和服务器都需要持续监视其NetworkStream
个对象以获取新数据。收到数据时,应将其附加到某种数据缓冲区,直到收到足够的数据构成完整的消息。收到适当数量的数据后,您可以尝试解析其中的消息并做出适当的响应。
基本上,您需要设置如下所示的逻辑:
var data = new byte[1024];
var dataLength = 0;
var dataBuffer = new MyCustomDataBuffer();
while (true)
{
while (stream.DataAvailable)
{
dataLength = stream.Read(data, 0, data.Length);
dataBuffer.Append(data, dataLength);
while (dataBuffer.ContainsCompleteMessage())
{
dataBuffer.ProcessMessage();
}
}
}
这个例子的控制流程大大简化了,但它应该得到了这个想法。我也没有提供MyCustomDataBuffer
的实现,但写这样的类并不太复杂;实际上它只是一个字节流。
我们如何知道我们是否收到了完整的消息?嗯,这就是协议的要点:建立允许我们了解这些事情的规则。让我们考虑一个数据协议的简单示例,其中每条消息由相同的两部分组成:
使用此协议,我们知道所有消息的长度至少为两个字节(理论上最小的有效消息为00 02
,表示空字符串)。我们也知道消息的前两个字节告诉我们消息的总大小,所以我们知道何时停止读取数据。
因此,要从上面的代码实现ContainsCompleteMessage()
方法,我们需要:
一旦我们知道我们有一个有效的消息 - 我们知道它有多大 - 我们所要做的就是从我们的数据缓冲区中删除前N个字节(其中N是消息的大小),然后拉消息字符串的相关段之外的消息字符串:
// here, 'msg' is a byte array that contains just the message data
var msgString = Encoding.UTF8.GetString(msg, 2, msg.Length - 2);
switch (msgString)
{
case "kill": KillServer(); break;
// etc.
}
我在此描述的协议将满足您在网络上发送短字符串的需求。通用它可以让你发送更复杂的对象;您只需添加指定消息布局的其他元数据。我把它作为读者的练习。