首页 > 编程语言 >c#中tcp异步

c#中tcp异步

时间:2023-06-16 20:44:42浏览次数:49  
标签:异步 stream tcpClient c# tcp richTextBox1 private new 服务端

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Demo.BytesIO.TCP_Client
{
public partial class Form1 : Form
{
// 连接tcp
private TcpClient tcpClient =null;
private NetworkStream stream = null;
// 创建一个负责监听服务端请求的线程
Thread threadClient = null;

public const int TCPBufferSize = 1460; // 缓存的最大数据个数
public byte[] TCPBuffer = new byte[TCPBufferSize]; // 缓存数据的数组
public Form1()
{
InitializeComponent();
}

 

 

 

/*==================同步处理方法============*/

/// <summary>
/// 同步连接按钮事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
//private void tbConnect_Click(object sender, EventArgs e)
//{
// if(string.IsNullOrEmpty(tbStrIp.Text) == false && string.IsNullOrEmpty(tbIntPort.Text) == false)
// {
// try
// {
// string strIp = tbStrIp.Text;
// int intPort = int.Parse(tbIntPort.Text);

// if (tcpClient.Connected) // 如果已经连接了,点击连接,重新连接服务端
// {
// ReConnect(strIp, intPort);
// richTextBox1.AppendText("已经成功连接服务器\r\n");
// }
// else
// {
// // 连接服务端
// tcpClient.Connect(strIp, intPort);
// NetworkStream networkStream = tcpClient.GetStream(); // 获取服务端的网络流数据

// richTextBox1.AppendText("成功连接服务器\r\n");
// if (ConnectStatus())
// {
// stream = tcpClient.GetStream();
// }
// // 接收服务端的消息线程
// //创建一个线程 用于监听服务端发来的消息
// threadClient = new Thread(Recive);
// //将窗体线程设置为与后台同步
// threadClient.IsBackground = true;
// //启动线程
// threadClient.Start();
// }
// }
// catch (Exception ex)
// {
// MessageBox.Show(ex.ToString(), "提示");
// }
// }
// else
// {
// MessageBox.Show("请输入IP地址或端口号!", "提示");
// }

//}
/// <summary>
/// 直接获取端口字符串数据没有则返回空
/// </summary>
private void Recive()
{
//定义一个1M的内存缓冲区 用于临时性存储接收到的信息
byte[] data = new byte[1024];
String responseData = String.Empty;
while (true) // 持续监听服务端发来的消息
{
try
{
int bytes = stream.Read(data, 0, data.Length);
responseData = Encoding.Default.GetString(data, 0, bytes);
if(responseData != null)
{
// 显示在日志上
// richTextBox1.AppendText(responseData); //会报错:控件不能控制线程,用线程控制线程
//用Action线程委托操作
Invoke((new Action(()=> {
richTextBox1.AppendText($"[{DateTime.Now}]:{responseData}\r\n");
})));
if (responseData == "")
{
Invoke((new Action(() => {
richTextBox1.AppendText($"[{DateTime.Now}]:服务端异常断开连接\r\n");
})));
stream.Close();
tcpClient.Close();
threadClient.Abort();
break;
}
}
}
catch (ObjectDisposedException odex)
{
//服务端异常断开连接,然后点击断开出现的异常
// 结束循环
richTextBox1.AppendText("已断开连接\r\n");
break;
}
}
}

/// <summary>
/// 断开服务端
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void tbDisconnect_Click(object sender, EventArgs e)
{
try
{
//先判断连接状态
if (ConnectStatus()) // 存在连接服务端
{
tcpClient.Close();
richTextBox1.AppendText("已断开连接\r\n");
}
else
{
MessageBox.Show("未存在连接!!");
}
}
catch
{

}
}
/// <summary>
/// 清空接收按钮事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnClearConnect_Click(object sender, EventArgs e)
{
richTextBox1.Clear();
}
/// <summary>
/// 发送按钮事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
//private void btnSend_Click(object sender, EventArgs e)
//{
// // 获取输入框中的内容
// string initData = richTextBox2.Text;
// try
// {
// if(initData.Length > 0)
// {
// // 转换成字节
// byte[] data = Encoding.Default.GetBytes(initData);
// // 数据流写出
// stream.Write(data, 0, data.Length);
// // 在日志中显示
// richTextBox1.AppendText($"[{DateTime.Now}]:{initData}\r\n");

// }
// }
// catch (Exception)
// {

// }

//}
/// <summary>
/// 清空发送按钮事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnClearSend_Click(object sender, EventArgs e)
{
// 清空输入框里的内容
richTextBox2.Clear();
}

/// <summary>
/// 连接的状态
/// </summary>
/// <returns></returns>
private bool ConnectStatus()
{
try
{
return tcpClient.Connected;
}
catch
{
return false;
}
}
/// <summary>
/// 服务端状态
/// </summary>
/// <returns></returns>
private bool ServerStatus()
{
return false;
}
/// <summary>
/// 重新连接服务端
/// </summary>
/// <param name="strIp"></param>
/// <param name="intPort"></param>
private void ReConnect(string strIp, int intPort)
{
try
{
if (tcpClient != null)
{
tcpClient.Close();
}
tcpClient = new TcpClient(strIp, intPort);
if (tcpClient.Connected)
{
stream = tcpClient.GetStream();
}
}
catch (Exception ex)
{

}
}

 

 


/*==========================异步处理方法====================*/

/// <summary>
/// 连接按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void tbConnect_Click(object sender, EventArgs e)
{
// 判断IP地址和端口号不能为空
if(string.IsNullOrEmpty(tbStrIp.Text) == false && string.IsNullOrEmpty(tbIntPort.Text) == false)
{
try
{
// 获取IP地址和端口号
string strIP = tbStrIp.Text;
int intPort = int.Parse(tbIntPort.Text);

// 创建一个tcpClient
tcpClient = new TcpClient();
// 根据服务端的IP地址和端口号 异步连接服务器
tcpClient.BeginConnect(strIP, intPort, new AsyncCallback(ConnectCallback), tcpClient);
}
catch (Exception)
{

}
}
else if(string.IsNullOrEmpty(tbIntPort.Text))
{
MessageBox.Show("请输入IP地址", "提示");
}
else if (string.IsNullOrEmpty(tbIntPort.Text))
{
MessageBox.Show("请输入端口", "提示");
}
}

/// <summary>
/// 连接异步回调函数
/// </summary>
/// <param name="ar"></param>
private void ConnectCallback(IAsyncResult ar)
{
TcpClient tcp = (TcpClient)ar.AsyncState;
// System.InvalidOperationException:“不允许对非连接的套接字执行此操作。”
//stream = tcp.GetStream();
stream = tcpClient.GetStream();//创建于服务端连接的数据流
try
{
tcp.EndConnect(ar);
// 设置异步读取数据,接收的数据缓存到TCPBuffer,接收完成跳转ReadCallback函数
stream.BeginRead(TCPBuffer, 0, TCPBufferSize, new AsyncCallback(ReadCallback), stream);
Invoke((new Action(()=> {
richTextBox1.AppendText($"[{DateTime.Now}] 服务端连接成功!\r\n");
})));
}catch(Exception ex)
{
Invoke((new Action(()=> {
richTextBox1.AppendText($"[{DateTime.Now}] 连接失败:{ex.ToString()}\r\n");
})));
}
}
/// <summary>
/// 接收服务端数据的回调函数
/// </summary>
/// <param name="ar"></param>
private void ReadCallback(IAsyncResult ar)
{
/*无法将类型为“System.Net.Sockets.NetworkStream”的对象强制转换为类型“System.Net.Sockets.TcpClient”。”
*TcpClient tcp = (TcpClient)ar.AsyncState;
*int CanReadLen = tcp.Client.EndReceive(ar);
* 用这种方式需要把stream.BeginRead(TCPBuffer, 0, TCPBufferSize, new AsyncCallback(ReadCallback), stream);
* 最后面的一个参数改为TcpClient类型,否则会报最上面的类型无法转化的错误
*/
NetworkStream networkStream = (NetworkStream)ar.AsyncState;
int CanReadLen = networkStream.EndRead(ar);
if (CanReadLen > 0)
{
string data = Encoding.Default.GetString(TCPBuffer, 0, CanReadLen);
Invoke((new Action(() => {
richTextBox1.AppendText($"[{DateTime.Now}]:{data}\r\n");
})));
// 设置异步读取数据,接收的数据缓存到TCPBuffer,接收完成跳转ReadCallback函数
stream.BeginRead(TCPBuffer, 0, TCPBufferSize, new AsyncCallback(ReadCallback), stream);
}
else
{ //异常
Invoke((new Action(() => {
richTextBox1.AppendText($"[{DateTime.Now}] 异常断开!\r\n");
})));
try
{
tcpClient.Close();
stream.Close();
}
catch (Exception) { }
}

}

/// <summary>
/// 发送按钮事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSend_Click(object sender, EventArgs e)
{
//stream = tcpClient.GetStream(); // 创建于服务器连接的数据流
// 获取文本框中的内容
string rtbStr = richTextBox2.Text;
try
{
if (rtbStr.Length > 0) //文本框里有内容
{
// 转换成字节
byte[] data = Encoding.Default.GetBytes(rtbStr);
// 异步发送数据
//stream.BeginWrite(data, 0, data.Length, new AsyncCallback(SendCallback), stream);
// 发送数据
stream.Write(data, 0, data.Length);
Invoke((new Action(() => {
richTextBox1.AppendText($"[{DateTime.Now}]:{rtbStr}\r\n");
})));
}
else
{
Invoke((new Action(() => {
richTextBox1.AppendText("请输入内容");
})));
}
}
catch (Exception) { }
}
}
}

标签:异步,stream,tcpClient,c#,tcp,richTextBox1,private,new,服务端
From: https://www.cnblogs.com/yjm8023/p/17486480.html

相关文章

  • ARC117F Gateau
    题意有一个\(2N\)个位置的圆,每个位置可以放任意多个物品(可以不放)。有\(2N\)条要求,形如第\(i\simi+N-1\)范围内的位置上总共至少有\(A_i\)个物品(\(0\lei<2N\),其中第\(j(j\ge2N)\)号位置其实是\(j-2N\)号)。问放置的物品总数至少为多少。\(1\leN\le1.5\times10^......
  • docker 安装kafka
    dockerrun-d--namezookeeper--publish2181:2181--volume/etc/localtime:/etc/localtimezookeeper:latestdockerrun-d--namekafka--publish9092:9092--linkzookeeper--envKAFKA_ZOOKEEPER_CONNECT=zookeeper:2181--envKAFKA_ADVERTISED_HOST_NAME=kaf......
  • javaScript核心知识点
      一、JavaScript简介       一、JavaScript语言的介绍:JavaScript是基于对象和原型的一种动态、弱类型的脚本语言       二、JavaScript语言的组成:JavaScript是由核心语法(ECMAScript)、文档对象模型(DOM)、浏览器对象模型(BOM)组成的       三......
  • springBoot 读取application.yml及优先级
    1.回顾之前的web.xml的加载方式  2.springBoot加载application.yml方式1.Application.run方法中的ConfigurableEnvironmentenvironment=this.prepareEnvironment(listeners,bootstrapContext,applicationArguments);是准备环境,里面会加载配置文件 2.prepareEnviron......
  • c++一些零碎记录
    c++11alignasstructalignas(8)S{}//定义结构体同时指定分配给结构体的大小为8字节alignof(与内存对齐相关)structobj{chara;intb;}alignof(obj)=4;//alignof(obj)=4表示对于obj,其内存对齐是以多少字节为单位对齐对于单个变量char其alignof(char)=1,单个字节对齐......
  • opcenter camstar designer基础知识-- Labels
    “标签”窗口用于查看系统标签以及添加、移除和查找用户标签可使用“标签”窗口中的按钮来执行这些功能,也可以在选择树区域中右键单击打开快捷菜单,然后选择以下选项:  系统有两种常规类型的标签:system和user 系统标签名称具有前缀CSI。这些标签又划分为多个不同的类......
  • Vue进阶(幺贰陆):表格复用 TypeError: _self.$scopedSlots.default is not a function解
    (文章目录)一、前言在使用elementUI的el-table组件时,表头应用v-if判断来动态显示,正常来说这样的操作是没有问题的,但是如果在这基础上使用<templateslot-scope="scope">操作的话,表头一旦切换就会报错,错误信息如下:_self.$scopedSlots.defaultisnotafunction二、解决方......
  • Journal of Electronic Imaging投稿分享
    JournalofElectronicImaging投稿分享在研究生阶段中的第一篇论文,前后总共三个月,还是很开心的!!!附下中稿图片 这个期刊从二月份开始投的,然后三月份给了大修,大修时间一个月。在四月份左右提交了修改稿,最终五月份就给了录用通知!总的来说,速度还是很快的。附下两次的审稿进度。......
  • Mac上将本地项目上传到Github
    请查看:https://www.jianshu.com/p/ee678badb842如果出现:fatal:remoteoriginalreadyexists就先删除已存在的:$gitremotermorigin再执行:$ gitremoteaddoriginyour_github_project_ssh_address......
  • 加密解密(ASCLL码)
    #include<iostream>#include<string>usingnamespacestd;intmain(intargc,char**argv){ stringa; cin>>a; intb; charc; for(inti=0;i<a.size();i++){ c=a[i]; cout<<"第"<<i<<"位:"<&l......