实验环境:Python3.7.0
socket格式:
socket([family[, type[, protocol]]])
使用给定的协议族(协议族决定了socket的地址类型,在通信中必须采用对应的地址)、套接字类型、协议编号来创建套接字。若用socket.socket()来创建套接字,则采用默认参数为(socket.AF_INET,socket.SOCK_STREAM,0)。
socket([family[, type[, protocol]]]) | |
参数 | 描述 |
协议族(family) | AF_INET:使用的是IPV4,默认参数; AF_INET6:使用IPV6; AF_UNIX:只能够用于单一的Unix系统进程间通信,要用一个绝对路径名作为地址。 |
套接字类型(type) | SOCK_STREAM:流式socket,TCP连接方式,默认参数 ; SOCK_DGRAM:数据包式,不可靠UDP; SOCK_RDW:可靠UDP形式; SOCK_SEQPACKET:可靠的连续数据包服务; SOCK_RAW:原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。 |
指定协议(protocol) | 常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。默认为0,表示会自动选择type类型对应的默认协议,可省略。 |
Socket编程涉及到的部分常用函数:
socket函数 | 描述 |
服务器端socket函数 | |
bind(address) | 将套接字绑定到地址, 在AF_INET下,以元组(ip,port)的形式表示地址。 |
listen(number) | 开始监听TCP连接,number表示操作糸统可以挂起的最大连接数量,可省略,默认为1。 |
accept() | 接受TCP连接并返回元组:(socket,address),socket为新的套接字对象,address是连接客户端的地址也是元组:(ip,port)。 |
客户端socket函数 | |
connect(address) | 连接地址为address处的套接字。address的格式为元组:(ip,port)。 |
公共socket函数 | |
socket() | 创建套接字。 创建TCP socket: tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 或 tcp_socket = socket.socket() 创建UDP socket: udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) |
send(string[,flag]) | 发送TCP数据。将string发送给此连接的套接字,flag提供有关消息的其他信息,通常可以忽略。Python2.x数据以字符串类型返回,Python3.x以上数据以byte类型发送和接收,所以Python3.x以上发送接收数据要进行编码。 |
sendall(string[,flag]) | 完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。 |
sendto(string[,flag],address) | 发送UDP数据,也可用于TCP数据发送。address为元组:(ip,port),指接收数据的套接字的远程地址。 |
recv(bufsize[,flag]) | 接收TCP套接字的数据。bufsize指定要接收的最大数据量。 |
recvfrom(bufsize[.flag]) | 接收UDP套接字的数据,也可接收TCP套接字的数据。与recv()类似,但返回值是元组:(data,address)。address是发送数据的套接字地址格式为元组:(ip,port)。 |
close() | 关闭套接字。 |
TCP-Socket编程
TCP通信的基本流程如下图所示:
TCP-Socket编程(一):简单的TCP服务器与TCP客户端
代码定位:TCP客户端与TCP服务器端建立连接。
服务器端代码:
#Python3.7.0
#导入socket模块
import socket
#创建套接字 或使用server = socket.socket()
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#定义绑定的ip和端口,用元组定义
ip_port = ('127.0.0.1', 8888)
#绑定监听:bind(address),在AF_INET下,以元组(ip,port)的形式表示地址
server.bind(ip_port)
#设置最大连接数,默认为1
server.listen(5)
print("等待数据连接中……")
#接受客服端数据请求:accept()返回元组(conn,address),将接受到的客户端的socket对象保存到conn,address是连接客户端的地址也是元组:(ip,port)
conn, address = server.accept()
'''
向客服端返回连接信息
(注意:python3.x以上,网络数据的发送接收都是byte类型,
发送接收String类型数据时需要对数据进行编码(发送:messages.enconde();接收后转为String类型:messages.deconde()),pyhon2.x则直接发送数据无须编码。)
'''
messages = "连接成功!"
conn.send(messages.encode())
#关闭连接
conn.close()
客户端代码:
#Python3.7.0
#导入模块
import socket
#创建套接字
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#访问的服务器的ip和端口,用元组定义
ip_port = ("127.0.0.1", 8888)
#连接服务器主机:connect(address),address的格式为元组:(ip,port)
client.connect(ip_port)
#接收服务器发送或响应的数据
messages = client.recv(1024)
#打印接收的数据
#python3.x以上数据要编码(发送:messages.enconde();接收后转为String类型:messages.deconde())
print(messages.decode())
#关闭连接
client.close()
运行效果:
TCP-Socket编程(二):TCP服务器与同一个TCP客户端连续通信
代码定位:实现TCP服务器与TCP客户端相互连续通信。
服务器端代码:
#Python3.7.0
#导入socket模块
import socket
#创建套接字
server = socket.socket()
#定义绑定的ip和端口,用元组定义
ip_port = ('127.0.0.1', 8888)
#绑定监听
server.bind(ip_port)
#设置最大连接数,默认为1
server.listen(5)
#不断接受连接:one by one
while True:
print("等待数据连接中……")
#接受客服端数据请求
conn, address = server.accept()
'''
向客服端返回信息
(注意:python3.x以上,网络数据的发送接收都是byte类型,
发送接收String类型数据时需要对数据进行编码(发送:messages.enconde();接收后转为String类型:messages.deconde()),pyhon2.x则直接发送数据无须编码)
'''
messages = "连接成功!"
conn.send(messages.encode())
#计数信息条数
count = 0
#一个连接中,不断的接受客户端发来的数据
while True:
data = conn.recv(1024)
#打印客户端发来的数据信息
print(data.decode())
#判断是否退出当前连接,等在下一个连接
if data == b'exit':
break
#处理客户端数据(如:响应请求等)
count = count + 1
string = "第" + str(count) + "条信息:" + data.decode()
conn.send(string.encode())
#主动关闭连接
conn.close()
客户端代码:
#Python3.7.0
#导入模块
import socket
#创建套接字
client = socket.socket()
#访问的服务器的ip和端口,用元组定义
ip_port = ("127.0.0.1", 8888)
#连接服务器主机
client.connect(ip_port)
#同一链接中,不断向服务器发生数据或请求
while True:
#接收服务器发送或响应的数据
data = client.recv(1024)
#打印接收的数据;python3.x以上数据要编码(发送:data.enconde();接收后转为String类型:data.deconde())
print(data.decode())
messages = input("请输入发生或请求的数据(exit退出):")
client.send(messages.encode())
if messages == 'exit':
break
'''
#接收服务器发送或响应的数据
data = client.recv(1024)
#打印接收的数据;python3.x以上数据要编码(发送:data.enconde();接收后转为String类型:data.deconde())
print(data.decode())
'''
#关闭连接
client.close()
运行效果:
TCP-Socket编程(三):TCP服务器与多个TCP客户端同时进行连续通信
代码定位:以上两个程序都不能实现多个客户端与同一个服务器同时进行连接并相互通信。这里我们引入多线程来达到多个客户端同时与同一个服务器进行通信的目的,此外用Python的socketserver模块也可以实现此功能,有兴趣的可以自行学习。
服务器端代码:
#Python3.7.0
#导入模块
import socket
import threading
import random
def handle_client():
#接受客户端请求链接
client, address = server.accept()
print("[*] Accept connection from: %s:%d" % (address[0], address[1]))
messages = "Hello World!"
client.send(messages.encode())
#连续与当前连接的客户端通信
while True:
#接受客户端数据
request = (client.recv(1024)).decode()
#判断是否结束通信
if request == 'exit':
break
print("[*] Received from %s:%d : %s" % (address[0], address[1], request))
#发送响应信息给客户端
client.send((str(random.randint(1,1000)) + ":"+ "ACK!").encode())
#关闭当前连接
client.close()
if __name__ == "__main__":
#创建套接字
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#定义绑定ip和端口
ip = '127.0.0.1'
port = 8888
#绑定监听
server.bind((ip, port))
#设置最大连接数,默认为1
server.listen(5)
print("[*] Listening on %s:%d" %(ip, port))
#循环开启线程,接受多个客户端的链接通信
while True:
#创建一个线程
client_handler = threading.Thread(target=handle_client)
#开启线程
client_handler.start()
客户端代码:客户端代码使用TCP-Socket编程(二)中客户端的代码。
运行效果:
UDP-Socket编程
UDP通信的基本流程如下图所示:
UDP-Socket编程(一):简单的UDP服务器与UDP客户端
代码定位:UDP服务器端与UDP客户端通信。
服务器端代码:
#Python3.7.0
#导入模块
import socket
#创建套接字
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#定义绑定的IP和端口
ip_port = ('127.0.0.1', 9999)
#绑定监听
server.bind(ip_port)
#循环接收客户端发送来的数据信息
while True:
data = server.recv(1024)
#打印接收的数据
print(data.decode())
'''
#recvfrom()返回的是一个元组
data = server.recvfrom(1024)
#打印结果:(messages,(ip,port))
print(data)
#data为返回元组的第一个值既数据信息messages,address为返回元组除去data的另一个值为一个元组(ip,port)
data, address = server.recvfrom(1024)
#打印结果显示为messages
print(data.decode())
#打印结果显示address元组:(ip,port)
print(address)
'''
客户端代码:
#Python3.7.0
#导入模块
import socket
#创建套接字
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#定义访问的服务器IP和端口
ip_port = ('127.0.0.1', 9999)
#循环向服务器发送数据
while True:
messages = input('输入要发送的数据(exit退出):')
#退出循环
if messages == 'exit':
break
#发送数据;注意跟TCP的区别
#sendto(string[,flag],address):发送UDP数据,address是形式为(ipaddr,port)的元组,指定远程地址
client.sendto(messages.encode(), ip_port)
#关闭连接
client.close()
运行效果:
注意:
1、先运行服务器端代码,再运行客户端代码。
2、由于服务器端运行后没有执行socket.close(),可能会导致重新运行服务器端代码时出现报错,原因可能是服务器端进程相没有结束,同一端口被占用,请在任务管理器中结束相应进程再重新运行代码。
3、python3.x以上,网络数据messages的发送接收都是byte类型,若要发送接收String类型数据时需要对数据进行编码(发送:messages.enconde();接收后转为String类型:messages.deconde()),pyhon2.x则直接发送数据无须编码。
参考资料:
1.https://www.imooc.com/learn/1031
2.https://blog.csdn.net/rebelqsp/article/details/22109925