好的,我研究了一下异步TCP网络连接。我试着做了一个,但失败了。我要做的是确保服务器或客户端始终准备好接收聊天,并且能够随时发送聊天。我不希望他们处于备用模式。
例如,当客户端等待接收时服务器发送,因此客户端无法在此时发送。
我不想那样!
在Windows应用程序上执行了此操作。一旦我连接上,系统资源就猛增到100%。=/
服务器代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace AsyncServerChat
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Socket g_server_conn;
private byte[] g_bmsg;
private bool check = false;
private void Form1_Load(object sender, EventArgs e)
{
IPEndPoint local_ep = new IPEndPoint(IPAddress.Any, 9050);
Socket winsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
winsock.Bind(local_ep);
winsock.Listen(5);
winsock.BeginAccept(new AsyncCallback(Accept), winsock);
}
private void Accept(IAsyncResult iar)
{
Socket server_conn =(Socket) iar.AsyncState;
g_server_conn = server_conn.EndAccept(iar);
//label1.Text = "Connected. . .";
while (g_server_conn.Connected && check == false)
{
g_bmsg = new byte[1024];
check = true;
g_server_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), g_server_conn);
}
}
private void Send(IAsyncResult iar)
{
Socket server_conn = (Socket)iar.AsyncState;
server_conn.EndSend(iar);
}
private void Recieve(IAsyncResult iar)
{
Socket server_conn =(Socket) iar.AsyncState;
server_conn.EndReceive(iar);
if (g_bmsg.Length != 0)
{
label1.Text = Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length);
check = false;
}
}
private void sendButton_Click(object sender, EventArgs e)
{
string strmsg = textBox1.Text;
byte[] bmsg= Encoding.ASCII.GetBytes(strmsg);
g_server_conn.BeginSend(bmsg, 0, bmsg.Length, SocketFlags.None, new AsyncCallback(Send), g_server_conn);
}
}
}
顾客
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace AsyncClientChat
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Socket g_client_conn;
byte[] g_bmsg;
private bool check = false;
private void Form1_Load(object sender, EventArgs e)
{
}
private void connectButton_Click(object sender, EventArgs e)
{
IPEndPoint remote_ep = new IPEndPoint(IPAddress.Parse(textBox1.Text), 9050);
g_client_conn = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
g_client_conn.BeginConnect(remote_ep, new AsyncCallback(Connect), g_client_conn);
}
private void Connect(IAsyncResult iar)
{
Socket client_conn =(Socket) iar.AsyncState;
client_conn.EndConnect(iar);
while (g_client_conn.Connected)
{
g_bmsg = new byte[1024];
check = true;
g_client_conn.BeginReceive(g_bmsg, 0, g_bmsg.Length, SocketFlags.None, new AsyncCallback(Recieve), g_client_conn);
}
}
private void Send(IAsyncResult iar)
{
Socket client_conn = (Socket)iar.AsyncState;
client_conn.EndSend(iar);
}
private void Recieve(IAsyncResult iar)
{
Socket client_conn = (Socket)iar.AsyncState;
client_conn.EndReceive(iar);
if (g_bmsg.Length != 0)
{
label1.Text = Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length);
check = false;
}
}
}
}
最佳答案
问题是客户端方法中的循环。
移除它,因为它循环无限地将CPU使用率提高到100%,而且它是无用的。
顺便说一句,您的代码中还有其他问题:
跨线程操作异常
例如,在您的while
方法中:Connect
实际上,您试图从另一个线程(监听接收到的MSG的线程)设置标签文本,这是不允许的;
这样做:
为标签文本创建setter方法:
private void SetLabelText(string txt)
{
if (label1.InvokeRequired)
label1.Invoke(new MethodInvoker(delegate { SetLabelText1(txt); }));
else
label1.Text = txt;
}
然后使用setter而不是直接调用
Client.Recieve
:SetLabelText(Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length));
编辑以回答操作注释:
有关什么是线程的良好和广泛解释,请查看其wikipedia page。
总之,简单地说,一个正在运行的进程包含一个或多个线程,这些线程是可以并发执行的代码的一部分。
从您的tcp示例开始,使用
label1.Text = Encoding.ASCII.GetString(g_bmsg, 0, g_bmsg.Length);
而不是label1.Text = ...
将阻塞Socket.Receive
调用的执行(我的意思是在包含Socket.BeginReceive
方法的调用之后的代码行将无法到达),直到收到某些内容。这是因为
Socket.Receive()
方法运行在下面代码的同一个线程上,并且在每个线程上,代码是按顺序执行的(即逐行执行)。相反,使用
Receive
,在场景后面创建一个新线程。这个线程可能会调用并停止Socket.Receive
方法,并且一旦接收到某些内容,它就会调用作为参数传递的方法。这使得
Socket.BeginReceive
是异步的,而Socket.Receive
是同步的,这就是为什么我知道另一个线程(当你听到异步词时,很可能你在处理多线程)因此,当您更改
Socket.BeginReceive
时,实际上是从另一个线程设置它:由Socket.Receive
创建的线程。关于c# - 简单的异步TCP聊天应用程序[C#],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3899784/