c# - 服务器(GUI)在启动后冻结。在控制台中工作正常
问题描述
服务器(图形用户界面)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace Server_ProfiChat
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
static readonly object _lock = new object();
static readonly Dictionary<int, TcpClient> list_clients = new Dictionary<int, TcpClient>();
public static void handle_clients(object o)
{
int id = (int)o;
TcpClient client;
lock (_lock) client = list_clients[id];
while (true)
{
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[1024];
int byte_count = stream.Read(buffer, 0, buffer.Length);
if (byte_count == 0)
{
break;
}
string data = Encoding.ASCII.GetString(buffer, 0, byte_count);
broadcast(data);
Console.WriteLine(data);
//var chatline = txtChat.Text;
Form1 formObj = new Form1();
formObj.txtChat.Text += data;
}
lock (_lock) list_clients.Remove(id);
client.Client.Shutdown(SocketShutdown.Both);
client.Close();
}
public static void broadcast(string data)
{
byte[] buffer = Encoding.ASCII.GetBytes(data + Environment.NewLine);
lock (_lock)
{
foreach (TcpClient c in list_clients.Values)
{
NetworkStream stream = c.GetStream();
stream.Write(buffer, 0, buffer.Length);
}
}
}
private void btnConnect_Click(object sender, EventArgs e)
{
int count = 1;
string serverIP = txtServerIP.Text;
int serverPort = Int32.Parse(txtServerPort.Text);
TcpListener ServerSocket = new TcpListener(IPAddress.Parse(serverIP), serverPort);
ServerSocket.Start();
while (true)
{
TcpClient client = ServerSocket.AcceptTcpClient();
lock (_lock) list_clients.Add(count, client);
Console.WriteLine("Someone connected!!");
Thread t = new Thread(handle_clients);
t.Start(count);
count++;
}
}
}
}
服务器(控制台)
using System;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
namespace testServ
{
class Program
{
static readonly object _lock = new object();
static readonly Dictionary<int, TcpClient> list_clients = new Dictionary<int, TcpClient>();
static void Main(string[] args)
{
int count = 1;
TcpListener ServerSocket = new TcpListener(IPAddress.Parse("192.168.0.169"), 123);
ServerSocket.Start();
while (true)
{
TcpClient client = ServerSocket.AcceptTcpClient();
lock (_lock) list_clients.Add(count, client);
Console.WriteLine("Someone connected!!");
Thread t = new Thread(handle_clients);
t.Start(count);
count++;
}
}
public static void handle_clients(object o)
{
int id = (int)o;
TcpClient client;
lock (_lock) client = list_clients[id];
while (true)
{
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[1024];
int byte_count = stream.Read(buffer, 0, buffer.Length);
if (byte_count == 0)
{
break;
}
string data = Encoding.ASCII.GetString(buffer, 0, byte_count);
broadcast(data);
Console.WriteLine(data);
}
lock (_lock) list_clients.Remove(id);
client.Client.Shutdown(SocketShutdown.Both);
client.Close();
}
public static void broadcast(string data)
{
byte[] buffer = Encoding.ASCII.GetBytes(data + Environment.NewLine);
lock (_lock)
{
foreach (TcpClient c in list_clients.Values)
{
NetworkStream stream = c.GetStream();
stream.Write(buffer, 0, buffer.Length);
}
}
}
}
}
客户端(控制台)
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace test_Clie
{
class Program
{
static void Main(string[] args)
{
IPAddress ip = IPAddress.Parse("192.168.0.166");
int port = 123;
TcpClient client = new TcpClient();
client.Connect(ip, port);
Console.WriteLine("client connected!!");
NetworkStream ns = client.GetStream();
Thread thread = new Thread(o => ReceiveData((TcpClient)o));
thread.Start(client);
string s;
while (!string.IsNullOrEmpty((s = Console.ReadLine())))
{
byte[] buffer = Encoding.ASCII.GetBytes(s);
ns.Write(buffer, 0, buffer.Length);
}
client.Client.Shutdown(SocketShutdown.Send);
thread.Join();
ns.Close();
client.Close();
Console.WriteLine("disconnect from server!!");
Console.ReadKey();
}
static void ReceiveData(TcpClient client)
{
NetworkStream ns = client.GetStream();
byte[] receivedBytes = new byte[1024];
int byte_count;
while ((byte_count = ns.Read(receivedBytes, 0, receivedBytes.Length)) > 0)
{
Console.Write(Encoding.ASCII.GetString(receivedBytes, 0, byte_count));
Console.Write(ns);
}
}
}
}
我是初学者,但对我来说似乎与线程有关?也因为它冻结了我看不到其余部分是否正常工作,关于如何改进工作流程的任何想法,如寻找错误的确切点?我浪费了很多时间搜索任何东西,因为我不知道如何正确测试、调试和查明我犯的错误。
感谢任何帮助=))
解决方案
流通常完全按照您的要求执行。如果您要求 10 个字节,则 aRead
将在有 10 个字节返回之前不会返回。stream.Read
不会做的是返回更少的字节,因为那是已收到的字节数。
此代码将阻塞,直到读取了 1024 个字节。
byte[] buffer = new byte[1024];
int byte_count = stream.Read(buffer, 0, buffer.Length);
if (byte_count == 0)
{
break;
}
这是你所期待的吗?
通常,基于字节的协议有一个标头,其中包含有效负载中的字节数。
想象一下下面的协议:
<stx><soh><len><eoh><payload><etx>
- stx = 传输开始
- soh =标题的开始
- len = 有效载荷的长度
- eoh = 标题结束
- etx = 传输结束
要读取一个完整的数据包,您必须读取 4 个字节,然后您必须读取足够的字节来完成有效负载,最后一个字节应该是 ETX。
byte[5] header;
stream.Read(buffer, 0, 4);
int payloadLength = header[2];
byte[] payload = new byte[payloadLength];
stream.Read(payload, 0, payloadLength);
stream.Read() == ETX;
推荐阅读
- javascript - 使用 Django 模板在 Javascript 中从数据库中获取数据
- android - 如何获得解决 Android 底页的目标状态?
- node.js - Docker Compose 与 React、Angular 和 Python 服务器
- plot - 如何在 Julia 中绘制形状
- php - 在php中计算带有条件的关联数组
- jakarta-ee - 无法将 HttpServletRequest 注入 jakarta 休息服务资源
- google-drive-api - 有没有办法在 iframe 中自动播放谷歌驱动器视频?
- azure-active-directory - Azure AD 应用程序会话
- html - HTML 选择一个文件夹和一个不存在的文件名
- python - JWT:如何在密码或用户名错误 Django REST 上实现我的自定义错误消息