本项目使用C#语言建立一个TCP通讯实例,并可以互相传递消息:
传送一下传智播客赵老师的视频课程
- 关键词解释:
(1)TCP协议
一种可以用于网络通信的数据传输协议,传输安全可靠不会有信息丢失,重点理解三次握手与四次分手。
(2)线程Thread
我们的主程序是一个线程,若是不开启多线程我们便无法在程序中执行特定的动作。
Thread th = new Thread(Receive);
th.IsBackground = true; //线程转为后台运行
th.Start(socketSend); //开启线程
(3)套接字Socket
(连结是一位点击20w的博主写的,十分通俗易懂,包括UDP/TCP等)
(客户端与服务器端Socket运行步骤)
服务器端:
第一步:创建一个用于监听连接的Socket对像;
第二步:用指定的端口号和服务器的ip建立一个EndPoint对像;
第三步:用socket对像的Bind()方法绑定EndPoint;
第四步:用socket对像的Listen()方法开始监听;
第五步:接收到客户端的连接,用socket对像的Accept()方法创建一个新的用于和客户端进行通信的socket对像;
第六步:通信结束后一定记得关闭socket;
客户端:
第一步:建立一个Socket对像;
第二步:用指定的端口号和服务器的ip建立一个EndPoint对像;
第三步:用socket对像的Connect()方法以上面建立的EndPoint对像做为参数,向服务器发出连接请求;
第四步:如果连接成功,就用socket对像的Send()方法向服务器发送信息;
第五步:用socket对像的Receive()方法接受服务器发来的信息 ;
第六步:通信结束后一定记得关闭socket;
Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
(徐泽IP4网络连结模式,当进行TCP通讯时要选择流传输Stream,传输类型为Tcp)
socketSend.Receive(buffer);//程序运行到这一步会暂停,直到接收到客户端传递的消息;
buffer为字节数组,因为TCP通过二进制计算机语言交流,因此记得要转译出来;
socketSend.Send(buffer); //用于发送消息,传递的内容一样为字节数组。
2. 服务器搭建:
新建winform项目,拖入Textbox、button、textlog等控件:
监听按钮代码:
在这里建立socket连结:
private void button6_Click(object sender, EventArgs e)
{
try //开启网络连结的地方,建议都加上try
{
//创建一个负责监听的socket
Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//创建IP地址与端口号
IPAddress ip = IPAddress.Any;//IPAddress.Parse(textServer.Text);
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(textport.Text));
//让负责监听的Socket绑定IP地址跟端口号
socketWatch.Bind(point);
ShowMsg("监听成功");
//设置监听队列
socketWatch.Listen(10);
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketWatch);
}
catch
{ }
}
服务器绑定得IP地址为IPAdress.Any,意味着可以接收任意IP的客户端;
完整代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Server01
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
/// <summary>
/// 监听按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button6_Click(object sender, EventArgs e)
{
try //开启网络连结的地方,建议都加上try
{
//创建一个负责监听的socket
Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//创建IP地址与端口号
IPAddress ip = IPAddress.Any;//IPAddress.Parse(textServer.Text);
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(textport.Text));
//让负责监听的Socket绑定IP地址跟端口号
socketWatch.Bind(point);
ShowMsg("监听成功");
//设置监听队列
socketWatch.Listen(10);
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketWatch);
}
catch
{ }
}
/// <summary>
/// 等待客户端的连结,并且创建一个与之对应的Socket
/// 线程中函数可以无参数,若有必须是obbject类型;
/// </summary>
Socket socketSend;
void Listen(object o)
{
Socket socketWatch = o as Socket;//将object转化为Socket
//创建一个负责通信的Socket,用于接收客户端的连结
while (true)
{
try
{
socketSend = socketWatch.Accept();
ShowMsg(socketSend.RemoteEndPoint.ToString() + "连结成功");
//开启一个新的线程,不停的接收客户端发来的消息
Thread th = new Thread(Receive);
th.IsBackground = true;
th.Start(socketSend);
}
catch
{ }
}
}
/// <summary>
/// 服务器不停的接收客户端发来的消息
/// </summary>
/// <param name="ob"></param>
void Receive(object ob)
{
Socket socketSend = ob as Socket;
while (true)
{
try
{
//客户端连结成功后,服务器应该接受客户端发来的消息
byte[] buffer = new byte[1024 * 1024 * 2];
//实际接收到的有效字节数
int r = socketSend.Receive(buffer);
//当不接受数据的时候,则跳出
if (r == 0)
{
break;
}
string str = Encoding.UTF8.GetString(buffer, 0, r);//从0开始解码到r个
ShowMsg(socketSend.RemoteEndPoint + ":" + str);
}
catch
{ }
}
}
/// <summary>
/// 服务器给客户端发送消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_Click(object sender, EventArgs e)
{
string str = textMsg.Text;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
socketSend.Send(buffer);
}
void ShowMsg(string str)
{
textLog.AppendText(str + "\r\n");
}
/// <summary>
/// 关闭线程检测
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
}
}
}
- 客户端:
另外新建一个winform项目,并拖入控件:
与服务器不同的是,客户端要指定需要连结服务器的IP地址,并且主动使用socket.Connect( )进行连结;
完整代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Client01
{
public partial class Form1 : Form
{
Socket socketSend;
public Form1()
{
InitializeComponent();
}
~Form1()
{
}
/// <summary>
/// 客户端消息发送按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_Click(object sender, EventArgs e)
{
string str = textMsg.Text.Trim();
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
socketSend.Send(buffer);
}
/// <summary>
/// 连结服务器按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button6_Click(object sender, EventArgs e)
{
try
{
//创建负责通信的Socket
socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//客户端要连结服务器
IPAddress ip = IPAddress.Parse(textServer.Text);
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(textport.Text));
//获得要连结的远程服务器应用程序的IP地址和端口号
socketSend.Connect(point);
ShowMsg("连结成功");
Thread thread = new Thread(Receive);
thread.IsBackground = true;
thread.Start();
}
catch
{ }
}
/// <summary>
/// 不停的接收服务端发来的消息
/// </summary>
void Receive()
{
while (true)
{
try
{
byte[] buffer = new byte[1024 * 1024 * 2];
int r = socketSend.Receive(buffer);
if (r == 0)
{
break;
}
string s = Encoding.UTF8.GetString(buffer, 0, r);
ShowMsg(socketSend.RemoteEndPoint + ":" + s);
}
catch
{ }
}
}
void ShowMsg(string str)
{
//textLog.AppendText(str + "\r\n");
this.Invoke(new Action(() =>
{
//this.textLog.Items.Add(serwe);
//textBox1.Text = "";
textLog.AppendText(str + "\r\n");
}));
}
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
}
#region
#endregion
}
}