- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在学习C#套接字编程。因此,我决定进行TCP聊天,其基本思想是:一个客户端将数据发送到服务器,然后服务器在线为所有客户端广播数据(在这种情况下,所有客户端都在字典中)。
当有1个客户端连接时,它按预期方式工作,当有多个客户端连接时,就会出现此问题。
服务器:
class Program
{
static void Main(string[] args)
{
Dictionary<int,TcpClient> list_clients = new Dictionary<int,TcpClient> ();
int count = 1;
TcpListener ServerSocket = new TcpListener(IPAddress.Any, 5000);
ServerSocket.Start();
while (true)
{
TcpClient client = ServerSocket.AcceptTcpClient();
list_clients.Add(count, client);
Console.WriteLine("Someone connected!!");
count++;
Box box = new Box(client, list_clients);
Thread t = new Thread(handle_clients);
t.Start(box);
}
}
public static void handle_clients(object o)
{
Box box = (Box)o;
Dictionary<int, TcpClient> list_connections = box.list;
while (true)
{
NetworkStream stream = box.c.GetStream();
byte[] buffer = new byte[1024];
int byte_count = stream.Read(buffer, 0, buffer.Length);
byte[] formated = new Byte[byte_count];
//handle the null characteres in the byte array
Array.Copy(buffer, formated, byte_count);
string data = Encoding.ASCII.GetString(formated);
broadcast(list_connections, data);
Console.WriteLine(data);
}
}
public static void broadcast(Dictionary<int,TcpClient> conexoes, string data)
{
foreach(TcpClient c in conexoes.Values)
{
NetworkStream stream = c.GetStream();
byte[] buffer = Encoding.ASCII.GetBytes(data);
stream.Write(buffer,0, buffer.Length);
}
}
}
class Box
{
public TcpClient c;
public Dictionary<int, TcpClient> list;
public Box(TcpClient c, Dictionary<int, TcpClient> list)
{
this.c = c;
this.list = list;
}
}
Thread.start()
传递2个参数。
class Program
{
static void Main(string[] args)
{
IPAddress ip = IPAddress.Parse("127.0.0.1");
int port = 5000;
TcpClient client = new TcpClient();
client.Connect(ip, port);
Console.WriteLine("client connected!!");
NetworkStream ns = client.GetStream();
string s;
while (true)
{
s = Console.ReadLine();
byte[] buffer = Encoding.ASCII.GetBytes(s);
ns.Write(buffer, 0, buffer.Length);
byte[] receivedBytes = new byte[1024];
int byte_count = ns.Read(receivedBytes, 0, receivedBytes.Length);
byte[] formated = new byte[byte_count];
//handle the null characteres in the byte array
Array.Copy(receivedBytes, formated, byte_count);
string data = Encoding.ASCII.GetString(formated);
Console.WriteLine(data);
}
ns.Close();
client.Close();
Console.WriteLine("disconnect from server!!");
Console.ReadKey();
}
}
最佳答案
从您的问题尚不清楚您具体遇到了什么问题。但是,检查代码揭示了两个重要问题:
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.Any, 5000);
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);
}
}
}
}
class Program
{
static void Main(string[] args)
{
IPAddress ip = IPAddress.Parse("127.0.0.1");
int port = 5000;
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));
}
}
}
lock
语句来确保list_clients
对象的线程进行独占访问。 Box
对象。集合本身由所有执行方法均可访问的静态字段引用,并且分配给每个客户端的int
值作为线程参数传递,因此线程可以查找适当的客户端对象。 0
的字节数完成。这是用于指示远程端点已完成发送的标准套接字信号。端点指示已使用Shutdown()
方法完成发送。要启动正常关闭,请使用“发送”原因调用Shutdown()
,指示端点已停止发送,但仍会接收。另一个端点一旦发送到第一个端点,便可以使用“both”的原因调用Shutdown()
,以指示它已完成发送和接收。 Thread.Join()
(即等待该线程退出),以确保在启动正常关闭过程后,它实际上不会关闭套接字,直到远程端点通过关闭其末端进行响应为止。 o => ReceiveData((TcpClient)o)
用作ParameterizedThreadStart
委托(delegate)是一种习惯用法,我更喜欢使用thread参数的强制转换。它允许线程入口点保持强类型。但是,该代码与我通常编写的代码并不完全相同。我一直坚持使用您的原始代码,同时仍然利用这个机会来说明这一惯用法。但实际上,我将使用无参数的ThreadStart
委托(delegate)来使用构造函数重载,并让lambda表达式捕获必要的方法参数:Thread thread = new Thread(() => ReceiveData(client)); thread.Start();
然后,根本就不需要强制转换(并且如果有任何参数是值类型,则无需进行任何处理即可)任何装箱/拆箱的开销……在这种情况下通常都不是关键问题,但仍然让我感觉更好:))。 Control.Invoke()
(或WPF程序中的Dispatcher.Invoke()
)。一种更复杂(也是更好的IMHO)的方法是对I/O使用async
/await
。如果您正在使用StreamReader
接收数据,则该对象已经具有可等待的ReadLineAsync()
和类似的方法。如果直接使用Socket
,则可以使用 Task.FromAsync()
方法将BeginReceive()
和EndReceive()
方法包装在一个等待中。无论哪种方式,结果都是尽管I/O异步发生,但补全仍在UI线程中处理,您可以在其中直接访问UI对象。 (在这种方法中,您将等待代表接收代码的任务,而不是使用Thread.Join()
,以确保您不会过早关闭套接字。)关于c# - 与多个客户端的C#TCP/IP简单聊天,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43431196/
我是 ZMQ 的新手。我发现 ZMQ 套接字实现比 winsock 简单得多。但我怀疑 “使用 ZMQ TCP 套接字创建的客户端可以与传统的 TCP 服务器通信吗?” 换句话说我的 ZMQ 客户端可
我想使用 TCP 协议(protocol) 将数据发送到 Logstash。为了发送数据,我正在使用 Node-RED。一个简单的配置如下所示: 在 Logstash 文件夹中,我创建了一个名为 no
当我尝试更改窗口缩放选项时,作为 root,我可以通过在 /proc/sys/net/中执行 net.ipv4.tcp_mem=16777000 来更改值。如果我必须更改这 100 个系统,那将需要大
明天做一些练习题,这道做不出来 TCP 服务器连接 TCP 客户端进行通信所需的最小套接字端口数是多少? 肯定只有两个吧?一个用于服务器,一个用于客户端,但这似乎是显而易见的。我的伙伴们认为 TCP
考虑一个存在一个服务器和多个客户端的场景。每个客户端创建 TCP 连接以与服务器交互。 TCP alive的三种用法: 服务器端保活:服务器发送 TCP 保活以确保客户端处于事件状态。如果客户端死了,
TCP TAHOE 和 TCP RENO 有什么区别。 我想知道的是关于 3-dup-ack 和超时的行为? SST 发生了什么变化? 谢谢! 最佳答案 TCP Tahoe 和 Reno 是处理 TC
大家早上好。我一直在阅读(其中大部分在堆栈溢出中)关于如何进行安全密码身份验证(散列 n 次,使用盐等)但我怀疑我将如何在我的 TCP 客户端中实际实现它-服务器架构。 我已经实现并测试了我需要的方法
在遍历 RFC793 时,我开始知道应该以这种方式选择初始序列号段重叠被阻止。 有人能解释一下如果发生重叠,重复段将如何影响 TCP? 最佳答案 不同的操作系统有不同的行为。参见 http://ins
你能举例说明一下tcp/ip中nagle算法的概念吗? 最佳答案 我认为Wikipedia在开头的段落中做得很好。 Nagle's document, Congestion Control in IP
似乎最大 TCP 接收窗口大小为 1GB(使用缩放时)。因此,仍然可以用一个连接填充 100Gb 管道的最大 RTT 是 40ms(因为 2 * 40E-3 * 100E9/8 = 1GB)。这会将这
考虑在两个 TCP 端点之间建立的 TCP 连接,其中一个调用: 关闭():此处,不允许进一步读取或写入。 关机(fd,SHUT_WR):这会将全双工连接转换为单工连接,其中调用 SHUT_WR 的端
我是在 Lua 中编写解析器的新手,我有两个简短的问题。我有一个包含 TCP 选项的数据包,如 MSS、TCP SACK、时间戳、NOP、窗口比例、未知。我基本上是在尝试剖析 TCP 选项字段中的未知
TCP 是否不负责通过在传输过程中发生丢失等情况时采取任何可能必要的措施来确保通过网络完整地发送流? 它做的不对吗? 为什么更高的应用层协议(protocol)及其应用程序仍然执行校验和? 最佳答案
考虑使用 10 Mbps 链路的单个 TCP (Reno) 连接。假设此链路不缓冲数据并且接收方的接收缓冲区比拥塞窗口大得多。设每个 TCP 段的大小为 1500 字节,发送方和接收方之间连接的双向传
考虑这样一个场景,有client-a和server-b。 server-b 禁用了 TCP keepalive。 server-b 没有任何应用程序逻辑来检查 TCP 连接是否打开。 client-a
我正在尝试用 Rust 编写回显服务器。 use std::net::{TcpStream, TcpListener}; use std::io::prelude::*; fn main() {
听说对于TCP连接,服务器会监听一个端口,并使用另一个端口发送数据。 例如,Web 服务器监听端口 80。每当客户端连接到它时,该服务器将使用另一个端口(比如 9999)向客户端发送数据(Web 内容
我试图了解带有标记 PSH 和标记 URG 的 TCP 段之间的区别。我阅读了 RFC,但仍然无法理解,其中一个在将数据发送到进程之前缓冲数据而另一个没有吗? 最佳答案 它们是两种截然不同的机制。 #
有第三方服务公开 TCP 服务器,我的 Node 服务器(TCP 客户端)应使用 tls Node 模块与其建立 TCP 连接。作为 TCP 客户端, Node 服务器同时也是 HTTP 服务器,它应
我正在发送一些 TCP SYN 数据包以获得 TCP RST 的返回。为了识别每个探测器,我在 TCP 序列字段中包含一个计数器。我注意到以下几点: 当SYN probe中的sequence numb
我是一名优秀的程序员,十分优秀!