要进行网络间的通信,首先要唯一标识一个进程,利用前面提到的IP和端口号我们可以唯一的标识一个进程。⽤这个标志与其它进程进⾏交互。这个就是网络编程,又称为socket(简称为套接字)编程。
1. socket对象的创建
socket(简称套接字)是进程间通信的⼀种⽅式,在Python中我们用socket模块来实现网络编程,在socket模块中一个socket函数可以创建socket对象。其中有两个参数,第一个参数可以选择AF_INET(用于Internet进程间通信)或AF_UNIX(用于同一台机器间进程的通信),实际工作中常用前者,因为前者也能实现同一台机器间进程的通信,第二个参数是套接字类型,可以是SOCK_STREAM(流式套接字,主要用于TCP协议)或SOCK_DGRAM(数据报套接字,主要用于UDP协议)
import socket
s = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
2. UDP协议
UDP(User Datagram Protocol):用户数据播报协议,是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。UDP不提供可靠性,它只把应用程序传给IP层的数据发送出去,但不能保证他们能达到目的地。由于UDP在发送数据前不在客户与服务器间建立一个连接,且没有超时重发等级制,故而传输速度极快。
UDP是一种面向无连接的协议,每次数据播报都是一个独立的信息,包括完整的源地址和目的地址,它在网络上以任何可能的路径传往目的地,至于能否达到目的地以及内容的正确性不能保证。
UDP可以实现广播发送。UDP传输数据时有大小限制,每个传输的数据包必须限定在64KB之内。UDP适用于语音播报、视频会议系统、QQ消息文件的上传和下载、TFTP、SNMP等。
3. 实现UDP客户端的数据传输和接受
创建一个UDP客户端程序的流程如下:1.创建客户套接字 2.发送和接受数据 3.关闭套接字
1.不绑定IP和端口
UDP传输数据时以gbk编码传输,接受到的信息要进行解码
import socket
# 创建socket对象
ss = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# 对方的IP和接收数据的端口组成的套接字 用来发送信息
address = ("192.168.14.30", 8080)
msg = input("输入发送的内容:")
# 发送信息
ss.sendto(msg.encode("gbk"), address)
# 接受对方发送过来的信息 限制传输的数据的大小 返回的是(msg, (ip, port))
# msg对方传输的数据 ip对方的ip port对方传输数据的端口
data = ss.recvfrom(1024)
print("接受来自于{} {}的信息:{}".format(data[1][0], data[1][1], msg.decode("gbk")))
# 关闭连接
ss.close()
2. 绑定IP和端口
如果仅仅是用于发送信息的话不用绑定端口,但想要接受信息必须绑定端口,
import socket
# 创建socket对象
ss = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# ""指的是本机
ss.bind("", 8081)
# 对方的IP和接收数据的端口组成的套接字 用来发送信息
address = ("192.168.14.30", 8080)
msg = input("输入发送的内容:")
# 发送信息
ss.sendto(msg.encode("gbk"), address)
# 接受对方发送过来的信息 限制传输的数据的大小 返回的是(msg, (ip, port))
# msg对方传输的数据 ip对方的ip port对方传输数据的端口
data = ss.recvfrom(1024)
print("接受来自于{} {}的信息:{}".format(data[1][0], data[1][1], msg.decode("gbk")))
# 关闭连接
ss.close()
3. 向UDP协议的软件发送信息
发送信息的格式如下:版本号:包编号:发送者姓名:发送者机器名:命令字:消息
这是个死循环,循环发送信息,很容易造成敌方软件死机,慎用。
import socket
s = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
address = ("192.168.14.4", 2425)
try:
while True:
# msg = input("请输入你要发送的信息:")
data = "1:12323434:垃圾胖子:QIKU-20180502BU:32:{}".format("垃圾胖子就是垃圾")
s.sendto(data.encode("gbk"), address)
except Exception as e:
print("发送错误,错误信息是", e)
finally:
s.close()
4.UDP广播
向当前网段的2425端口循环发送广播,这个没有实现成功,但程序运行不报错。
udp = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
udp.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
addr = ("<broadcast>", 2425)
while True:
msg = input(">>>")
udp.sendto(msg.encode("gbk"), addr)
i = 0
while i < 10:
(buf, address) = udp.recvfrom(2048)
print("接收到%s=====>%s" % (address, buf.decode("gbk")))
i += 1
udp.close()
print("successful")
4 UDP多线程编程
from threading import Thread, Lock
def send_msg(ip="192.168.14.30", port=8888):
import socket
s = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
tup = (ip, port)
while True:
# print(">>>", end="")
con = input("")
if con != "q":
s.sendto(con.encode("gbk"), tup)
else:
break
s.close()
def rec_msg(ip="192.168.14.30", port=8889):
import socket
ss = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# 绑定ip和端口用于接受信息
ss.bind((ip, port))
while True:
# 限制每秒接受的每件的大小
rec = ss.recvfrom(1024)
msg = rec[0].decode("gbk")
if msg != "q":
print("\n{}>>>".format(rec[1][0]), msg)
else:
print(">>>", "通话结束")
break
ss.close()
# 用多线程实现发送消息和接受消息
if __name__ == '__main__':
t1 = Thread(target=send_msg, args=["192.168.14.30", 8889])
t2 = Thread(target=rec_msg, args=["192.168.14.30", 8890])
t1.start()
t2.start()
5.用协程实现UDP传输数据
def send_msg(ip="192.168.14.30", port=8888):
import socket
s = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
tup = (ip, port)
while True:
print(">>>", end="")
con = input("")
if con != "q":
s.sendto(con.encode("gbk"), tup)
yield 0
else:
break
s.close()
def rec_msg(ip="192.168.14.30", port=8889):
import socket
ss = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# 绑定ip和端口用于接受信息
ss.bind((ip, port))
while True:
# 限制每秒接受的每件的大小
rec = ss.recvfrom(1024)
# rec=(b'\xbb\xd8\xd2\xe4\xd7\xdc\xcf\xeb\xbf\xde\xa3\xac\xd2\xbb\xb8\xf6\xc8\
# xcb\xb5\xc4\xd0\xd2\xb8\xa3\r\n', ('192.168.14.30', 8888))
# print(rec)
msg = rec[0].decode("gbk")
if msg != "q":
print("\n{}>>>".format(rec[1][0]), msg)
yield 0
else:
print(">>>", "通话结束")
break
ss.close()
if __name__ == '__main__':
t1 = send_msg()
t2 = rec_msg()
while True:
next(t1)
next(t2)
用协程实现UDP传输数据时,是双方轮流发送信息交流,若轮到一方发送信息,但它不发送信息,那么另一方不能发送信息。在用进程实现UDP数据传输时,由于进程间不支持input语句无法实现信息的输入,所以实现UDP传输数据用多线程最好。