Socket通信
效果展示
QQ20241112-114846
Socket的基本概念
Socket:它是网络通信的一个接口,代表了通信的一个端点。可以想象成一条虚拟的电话线,一端连接客户端,另一端连接服务器。
协议:Socket可以基于多种协议进行通信,最常用的是TCP(传输控制协议)和UDP(用户数据报协议)。TCP是面向连接、可靠的协议,而UDP是无连接、快速的协议。
Socket通信的基本流程
服务端:
创建Socket对象:使用socket()函数创建套接字。
绑定IP地址和端口号:使用bind()函数将Socket绑定到指定的IP和端口。
监听连接:使用listen()函数将Socket设置为监听状态,等待客户端连接。
接收连接请求:使用accept()函数接收客户端的连接请求,返回一个新的Socket实例,用于与客户端通信。
处理数据通信:服务端和客户端通过send()和recv()函数进行数据交换。
关闭连接:通信结束后,使用close()函数关闭Socket。
客户端:
创建Socket对象:客户端使用socket()函数创建套接字。
连接服务器:使用connect()函数连接到服务器的IP地址和端口。
数据通信:客户端与服务端通过send()和recv()函数交换数据。
关闭连接:通信结束后关闭Socket。
示例代码
Server服务器
窗体展示
查询本机IP地址
private void GetIp()//获取本机ip { string hostName = Dns.GetHostName(); // 获取本机名称 IPAddress[] ipList = Dns.GetHostAddresses(hostName);//本机ip(包括ipv4和ipv6)
foreach (IPAddress ip in ipList) // foreach不需要手动管理索引
{
uiComboBox_IP.Items.Add(ip.ToString().Trim());
// .Trim():去除转换后的字符串首尾的空白字符
// (虽然通常 IP 地址字符串没有空格,这里用 .Trim() 只是更保险的做法)。
}
// 查询IPV4,将查询到的第一个IP存放在文本框中
int index = 0;
foreach (IPAddress ip in ipList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
break;
// 查询到第一个后就 停止
}
index++;
}
uiComboBox_IP.SelectedIndex = index;
uiTextBox_Port.Text = "8081";
}
创建Socket()服务器
/// <summary>
/// 客户端的Socket
/// </summary>
private Socket clientSocket;
// 存储5M大小的数据
byte[] buffer = new byte[1024 * 1024 * 5];
private void btn_StartListen_Click(object sender, EventArgs e)
{
//AddressFamily–地址类型
//AddressFamily.InterNetwork–>IPV4
//SocketType.Stream–>以字节流的方式传输
//ProtocolType.Tcp–>传输协议;
// 1.创建服务器Socket()
Socket socket =new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 2.绑定IP和端口Bind()
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(uiComboBox_IP.SelectedItem.ToString()), int.Parse(uiTextBox_Port.Text));
socket.Bind(endPoint);
PrintfLog("绑定端口和IP成功");
Console.WriteLine();
// 3.监听连接Listen()
socket.Listen(10);
// 接收连接请求 Accept()
// Task.Run会在线程池中启动一个新任务
Task<bool> task = Task.Run(() =>
{
while (true)
{
//等待客户端建立连接
clientSocket=socket.Accept();
PrintfLog("服务器与客户端连接成功");
return true;
}
});
var awaiter= task.GetAwaiter();
awaiter.OnCompleted(() =>
{
Task.Run(() =>
{
while (true)
{
clientSocket.Receive(buffer);
if (buffer.Length == 0)
{
break;
}
string str = Encoding.UTF8.GetString(buffer,0, buffer.Length);
PrintfLog("接受数据:"+str);
}
});
});
}
文本显示框
void PrintfLog(string str)
{
if (this.InvokeRequired)
{
this.Invoke(new Action(() =>
{
// "F" 是标准的日期和时间格式字符串
textBox_Log.AppendText(DateTime.Now.ToString("F") + str + "\\r\\n");
}));
}
else
{
textBox_Log.AppendText(DateTime.Now.ToString("F") + str + "\\r\\n");
}
}
输入栏
private void btn_Send_Click(object sender, EventArgs e) { string str = textBox2.Text;
byte [] buffer=Encoding.UTF8.GetBytes(str);
clientSocket.Send(buffer,buffer.Length,0);
textBox2.Clear();
textBox_Log.AppendText(DateTime.Now.ToString("F") + "发送数据>:" + str + "\\r\\n");
}
关闭
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
小建议
可以把获取本机IP的函数放在Form1 构造函数中是为了在窗体启动时自动获取并显示本机的IP地址列表,以便用户可以直接选择一个IP地址,无需手动输入。
Client客户端
窗体展示
connect()连接
private Socket soketSend;
byte[] buff = new byte[1024 * 1024 * 5];
Thread thread;
private void button1_Click(object sender, EventArgs e) {
//AddressFamily–地址类型
//AddressFamily.InterNetwork–>IPV4
//SocketType.Stream–>以字节流的方式传输
//ProtocolType.Tcp–>传输协议;
soketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定端口和IP
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(textBox1.Text), int.Parse(textBox2.Text));
soketSend.Connect(endPoint);
textBox_log.AppendText("客户端连接服务器成功" + "\\r\\n");
thread = new Thread(() =>
{
while (true)
{
//Receive是有效数据得长度
int len = soketSend.Receive(buff);
if (len == 0)
{
break;
}
string str = Encoding.UTF8.GetString(buff, 0, len);
this.Invoke(new Action(() =>
{
textBox_log.AppendText(DateTime.Now.ToString("F") + "接受服务器消息:" + str + "\\r\\n");
}));
}
});
thread.Start();
}
发送消息send()
private void button2_Click(object sender, EventArgs e)
{
string str = textBox4.Text;
byte[] bytes= Encoding.UTF8.GetBytes(str);
soketSend.Send(bytes); textBox4.Clear();
textBox_log.AppendText(DateTime.Now.ToString("F") + "发送服务器消息:" + str + "\\r\\n");
}
关闭
private void close_Click(object sender, EventArgs e)
{
this.Close();
}
评论前必须登录!
注册