SOCKET编程
socket(套接字): 应用程序通常通过”套接字”向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。网络大多基于Socket通信。
通过IP+端口定位对方并发送消息的通信机制
分为UDP和TCP。
socket()函数
用 socket()函数来创建套接字,语法格式如下:
socket.socket([family[, type[, proto]]])
参数
family: 套接字家族可以使AF_UNIX或者AF_INET(ipv4协议族)
type: 套接字类型 。分为:面向连接的:SOCK_STREAM(使用TCP通信)和面向非连接:SOCK_DGRAM(使用UDP通信)
protocol: 一般不填默认为0.
Socket 对象(内建)方法
服务器端套接字:
s.bind() :绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。
s.listen() :TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5。
s.accept() :被动接受TCP客户端连接,(阻塞式)等待连接的到来。
客户端套接字:
s.connect(): 主动初始化TCP服务器连接。一般address的格式为元组(hostname,port)。
公共用途的套接字函数:
s.recv() :接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。
s.send() :发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。
s.recvfrom() :接收UDP数据,与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。
s.sendto(): 发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。
s.close() :关闭套接字。
UDP 编程
Server端流程 :
1. 建立socket,socket是负责具体通信的一个实例
2. 绑定,为创建的socket指派固定的端口和ip地址
3. 接受对方发送内容
4. 给对方发送反馈,此步骤为非必须步骤。
Client端流程:
1. 建立通信的socket 。
2. 发送内容到指定服务器 。
3. 接受服务器给定的反馈内容。
服务器案例:
# socket模块负责socket编程
import socket
# 模拟服务器的函数
def serverFunc():
# 1. 建立socket
# socket.AF_INET:使用ipv4协议族
# socket.SOCK_DGRAM: 使用UDP通信
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2. 绑定ip和port
# 127.0.0.1: 这个ip地址代表的是机器本身
# 9999: 随手指定的端口号
# 地址是一个tuple类型,(ip, port)
addr = ("127.0.0.1", )
sock.bind( addr )
# 接受对方消息
# recvfrom接受的返回值是一个tuple,前一项表示数据,后一项表示地址
# 参数的含义是缓冲区大小
# rst = sock.recvfrom(500)
data, addr = sock.recvfrom()
print(data)
# 发送过来的数据是bytes格式,必须通过解码才能得到str格式内容
# decode默认参数是utf8
text = data.decode()
print(text)
# 给对方返回的消息
rsp = "欢迎访问"
# 发送的数据需要编码成bytes格式,默认是utf8
data = rsp.encode()
sock.sendto(data, addr)
if __name__ == '__main__':
print("Starting server.........")
serverFunc()
print("Ending server........")
客户端案例:
import socket
def clientFunc():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
text = "Hello World!"
data = text.encode()
# 发送
sock.sendto(data, ("127.0.0.1", ))
data, addr = sock.recvfrom()
data = data.decode()
print(data)
if __name__ == '__main__':
clientFunc()
服务器程序要求永久运行,一般用死循环处理。
TCP编程
面向链接的传输,即每次传输之前需要先建立一个链接。
Server端的流程:
1.建立socket负责具体通信,这个socket其实只负责接受对方的请求,真正通信的是链接后重新建立的socket。
2. 绑定端口和地址。
3. 监听接入的访问socket。
4. 接受访问的socket,可以理解为建立了一个通讯的链接通路。
5. 接受对方的发送内容,利用接收到的socket接收内容。
6. 如果有必要,给对方发送反馈信息。
7. 关闭链接通路。
Client端流程:
1. 建立通信socket。
2. 链接对方,请求跟对方建立通路。
3. 发送内容到对方服务器。
4. 接受对方的反馈。
5. 关闭链接通路。
服务器案例:
import socket
def tcp_srv():
# 1. 建立socket负责具体通信。
# 需要用到两个参数
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 绑定端口和地址
# 此地址信息是一个元组类型内容,分两部分:字符串(代表ip)+端口
addr = ("127.0.0.1", )
sock.bind(addr)
# 3. 监听接入的访问socket
sock.listen()
while True:
# 4. 接受访问的socket,即建立一个通讯的链接通路
# accept返回的元组第一个元素赋值给skt,第二个赋值给addr
skt,addr = sock.accept()
# 5. 接受对方的发送内容
# 500代表接收使用的buffersize
msg = skt.recv()
msg = msg.decode()
rst = "Received msg: {0} from {1}".format(msg, addr)
print(rst)
# 6. 如果有必要,给对方发送反馈信息
skt.send(rst.encode())
# 7. 关闭链接通路
skt.close()
if __name__ == "__main__":
print("Starting tcp server.......")
tcp_srv()
print("Ending tcp server.......")
客户端案例:
import socket
def tcp_clt():
# 1. 建立通信socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 链接对方,请求跟对方建立通路
addr = ("127.0.0.1", )
sock.connect(addr)
# 3. 发送内容到对方服务器
msg = "Hello World!"
sock.send(msg.encode())
# 4. 接受对方的反馈
rst = sock.recv()
print(rst.decode())
# 5. 关闭链接通路
sock.close()
if __name__ == "__main__":
tcp_clt()