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) { }
}
}
}