文章目录
前言
本文整合了在局域网和互联网两种情况下的通信都应该怎么实现。网上的资料大多在教学socket使用时只会教学怎么实现局域网通信,导致还需要搜很多额外的资料才能接触到互联网通信。
这里需要注意,个人电脑上可以自己和自己通信成功,不代表代码放到其他计算机上就可以成功实现局域网或互联网通信,有条件一定要尝试两个不同计算机的通信。互联网通信如果不确定是不是依旧是使用的局域网通信方法,可以将一台计算机连路由器,一台计算机连手机热点(总之不是一个局域网内即可)。
一、局域网通信
1.1 基本原理和方法
1.1.1 获取本地ip
获取本地IP的方法有很多,这里介绍三种方法。分别是cmd中查看、python和C#调用函数查看。
1、cmd查看本地IP
此种方法有较大的局限性,因为本地ip在每次的分配过程中有可能会改变,想要每次都连接上对方的计算机需要每次都修改成当前的本地IP地址,添加了不必要的工作量。当然,如果只是初学做一个实验测试还是可以使用的。
1)首先win + R打开“运行”,在搜索框输入cmd。

2)点击确定后进入cmd命令窗口,输入ipconfig并回车执行命令,就可以得到结果。

可以看到图中标注红框的部分,192.168.0.103就是本机的本地IP。
2、python查看本地IP
由于本地IP每次分配是有很大可能是会变化的,所以大部分应用场景需要程序中直接获取,而不是在程序中写一个既定的IP地址。
import socket
ip = socket.gethostbyname(socket.gethostname())
socket.gethostname()将返回本机名称,socket.gethostbyname()参数放入本机名称后就会返回本地IP。
3、C#查看本地IP
using System.Net;
// 主机名
string hostName = Dns.GetHostName();
// 获取本机本地ip
IPAddress address = Dns.GetHostAddresses(hostName)[1];
步骤与python是类似的,就不多解释了。
注:其实也可以用python和C#的系统调用,调用cmd里输入的命令获取返回值。
1.1.2 实现局域网内的广播
在知道如何获取本机的本地IP之后,需要一种方法将服务端的IP地址告诉客户端,这个时候就需要用到广播技术(因为不通过广播告诉客户端服务端的IP地址,客户端将无从得知应该连接哪一个IP)。首先服务端要不断的广播,将自己的IP地址广播出去,随后客户端要接听广播。当客户端收到广播之后,再给服务端广播,告知服务端已经收到了服务端的广播。这时服务端进入监听阶段,服务端进入连接阶段。连接成功后就可以开始通信了。
整个流程如图所示:

当然,上述这种方式是线性的流程,只适用于有一个客户端时候的通信。之后再讲一种可以连接多个客户端的方法。
1、python进行广播的方法:
1)先用subprocess库获取子网掩码
import subprocess
subnet_mask = subprocess.getoutput("ipconfig | findstr 子网掩码")
subnet_mask = subnet_mask.split(":")[-1].strip()
2)根据本地IP和子网掩码获取广播地址
import ipaddress
network = ipaddress.ip_network(f"{
self.ip}/{
self.subnet_mask}", strict=False)
broadcast_address = network.broadcast_address
3)进行广播
# 创建一个socket对象, 参数表示使用IPV4和TCP协议
broadcast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 设置广播选项
# socket.SOL_SOCKET表示选项的级别是socket级别, 这意味着这个选项将应用于socket本身, 而不是特定的协议
# socket.SO_BROADCAST表示要设置的选项是广播选项, 决定了socket是否可以发送广播消息
# 1表示启用广播选项
broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
# 发送广播信息
broadcast_socket.sendto(info.encode("utf-8"), (self.broadcast_ip, self.port))
接收广播
broadcast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
broadcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
# 绑定到一个特定的端口
broadcast_socket.bind(("", broadcast_port))
# 接收广播信息
data, addr = broadcast_socket.recvfrom(1024)
2、C#进行广播的方法
1)获取子网掩码
using System.Net.NetworkInformation;
// 获取所有网络接口
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
// 遍历所有网络接口
foreach (var networkInterface in networkInterfaces) {
// 获取IP属性
var ipProperties = networkInterface.GetIPProperties();
// 获取单播地址
var unicastAddresses = ipProperties.UnicastAddresses;
// 获取IPv4单播地址
var ipv4UnicastAddresses = unicastAddresses.Where(x => x.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
foreach (var unicastAddress in ipv4UnicastAddresses) {
// 如果这个地址是本机的本地IP地址
if (unicastAddress.Address.ToString() == ip) {
// 获取子网掩码
var subnetMask = unicastAddress.IPv4Mask;
return subnetMask.ToString();
}
}
}
还有一种使用System.Management包的方法,代码量会低一些,但是这种方法只支持windows操作系统,所以这里给出的是另一种方法。
2)计算广播地址
string broadcastAddress = "";
// 分割IP地址和子网掩码
string[] ipArray = ip.Split('.');
string[] subnetMaskArray = subnetMask.Split('.');
// 计算广播地址
for (int i = 0; i < 4; i++) {
int ipInt = Convert.ToInt32(ipArray[i]);
int subnetMaskInt = Convert.ToInt32(subnetMaskArray[i]);
// 广播地址 = IP地址 | (~子网掩码 & 0xff)
int broadcastInt = ipInt | (~subnetMaskInt & 0xff);
// 拼接广播地址
broadcastAddress += broadcastInt.ToString() + ".";
}
broadcastAddress = broadcastAddress.Substring(0, broadcastAddress.Length - 1);
3)进行广播
// 创建UDP客户端
UdpClient udpClient = new UdpClient();
// 允许发送广播
udpClient.EnableBroadcast = true;
// 广播地址
IPEndPoint broadcastPoint= new IPEndPoint(broadcastAddress , 8080);
// 要发送的数据
byte[] bytes = Encoding.ASCII.GetBytes(info);
while (toBroadcast) {
// 发送数据
broadcastClient.Send(bytes, bytes.Length, broadcastPoint);
// 等待1秒
System.Threading.Thread.Sleep(delay);
}
接收广播
UdpClient udpClient = new();
IPEndPoint endPoint = new(IPAddress.Any, 8080);
// 绑定本地端口
udpClient.Client.Bind(endPoint);
while (true) {
// 接收广播
byte[] bytes = udpClient.Receive(ref endPoint);
string message = Encoding.ASCII.GetString(bytes);
Console.WriteLine($"接收到广播: {
message} 来自: {
endPoint.Address}:{
endPoint.Port}");
}
注:端口号是需要提前设定好的,是用来区别应用程序的标志。
1.1.3 进行局域网通信
1、python实现局域网通信
服务端需要一个socket对象,再让其绑定到本地IP和一个端口上,之后监听就可以了。如果需要发送消息就对连接上的客户端发消息,需要接收就接收。
import socket
# 创建一个socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定到一个特定的端口
server_socket.bind((ip, post))
# 开始监听连接, 参数表示最大连接数
server_socket.listen(max_connections)
print("服务器已启动,等待连接...")
while True:
# 接受一个连接, 返回一个客户的socket对象和客户端的IP地址
client_socket, client_address = server_socket.accept()
print(f"客户端{
client_address}已连接")
# 接收数据, 参数表示最大接收字节数
data = client_socket.recv(1024)
print(f"{
client_address}接收到数据:{
data.decode('utf-8')}")
# 发送反馈
client_socket.send("数据已接收".encode('utf-8'))
客户端需要连接服务端,连接上之后就可以发送和接收消息。
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 尝试连接服务器
client_socket.connect((server_ip, server_post))
2、C#实现局域网通信
服务端
// 创建服务端, TcpListener是采用TCP协议的监听器
// UDP协议的监听器是UDPListener
TcpListener server = new(IPAddress.Parse(serverIp), serverPost);
server.Start();
Console.WriteLine("服务器已启动,等待连接...");
while (true) {
// 接收客户端连接
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("客户端已连接");
// 获取客户端的网络流
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[1024];
// 读取客户端发送的数据
int bytesRead = stream.Read(buffer, 0, buffer.Length);
string data = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine($"接收到数据:{
data}");
// 反馈信息
byte[] response = Encoding.UTF8.GetBytes("数据已接收");
stream.Write(response, <

最低0.47元/天 解锁文章
&spm=1001.2101.3001.5002&articleId=136355308&d=1&t=3&u=d01dedeadf4e4190bd9140e63105b45e)
1万+

被折叠的 条评论
为什么被折叠?



