Socket基础
Socket的英文原义是"孔"或"插座",最初作为BSD UNIX的进程通信机制,也被称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。
基于服务器端和客户端的Socket原语
- socket():建立socket对象,相当于“打开”操作。socket原语的参数通常包括使用的传输层协议类型、网络层地址类型等。
- bind():绑定。参数传入要绑定的IP地址和端口。
IP地址必须是主机上的一个可用的地址(当主机上存在多个IP时,绑定地址0.0.0.0可以监听所有可用的IP);
端口必须是一个该Socket协议未被占用的端口,若一主机上的多个程序试图同时绑定到80端口时,只有一个程序能成功。
服务器端程序在listen()之前必须进行bind()操作,客户端程序若在connect()原语之前没调用bind(),系统会自动分配一个未被占用的地址和端口。 - listen():监听。只在服务器端有用,告诉操作系统开始监听之前绑定的IP地址和端口,可在参数中指定允许排队的最大连接数量
- connect():在客户端连接服务器。参数中需指定服务器端的地址和端口。要么与服务器端完成TCP 3次握手并建立连接,要么连接服务器失败
- accept():接收连接。只在服务器端有用,从监听到的连接中取出一个,并将其包装成一个新的Socket对象。完成accept()标志着Socket已完成了TCP链路建立阶段的3次握手。若无客户端连接请求,则accept()调用会阻塞等待。
- send():发送数据。以bytes类型进行数据的传输
- recv():接收数据。若Socket中无消息可读取,默认情况下recv()调用会被阻塞直至有消息到达
- close():关闭连接。一方调用,另一方收到后也调用close()关闭连接。
包socket封装了所有Python的原生Socket操作
实战在线(一):Socket TCP
TCP-Serverse.py:
'''TCP-Socket服务器端'''
import socket
import datetime
HOST = '0.0.0.0' #IP
PORT = 3434 #端口
#AF_INET说明使用IPv4地址,SOCK_STREAM指明TCP
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((HOST,PORT)) #绑定IP与端口
s.listen(1) #监听
while True:
conn,addr = s.accept() #接受TCP连接,并返回新的Socket对象
print ('Client %s connected!' % str(addr)) #输出客户端的IP地址
dt = datetime.datetime.now()
message = "Current time is "+str(dt)
mes_change = bytes(message,encoding='utf-8') #将str类型转码为经过编码后的bytes类型
conn.send(mes_change) #向客户端发送当前时间
print("Sent:",message)
conn.close() #关闭连接
TCP-Client.py:
'''TCP-Socket客户端'''
import socket
import os
HOST = '127.0.0.1'
PORT = 3434
#AF_INET说明使用IPv4地址,SOCK_STREAM指明TCP协议
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((HOST,PORT))
print("Connect %s:%d OK" % (HOST,PORT))
data = s.recv(1024) #接收最大长度为1024的数据
print ("Received: ",data)
s.close() #关闭连接
os.system('pause') #暂停程序,避免直接结束,看不到结果
效果图:
注意:先运行服务器端代码TCP-Serverse.py:,再运行客户端代码TCP-Client.py
服务器端代码主体处于while循环中,故程序将不断监听并一直运行,当有客户端连接成功后将当前系统时间发送给客户端并马上关闭连接
客户端的Socket端口号由系统自动分配
实战在线(二):Socket UDP
UDP相对于TCP在传输层提供更少的控制,没有建立连接、断开等概念,所以基于UDP的Socket通信过程也比TCP稍微简单。在UDP中可直接通过指定IP:Port进行数据收发。UDP Socket可以复用TCP中的socket()和bind()原语,除此之外,UDP属于自己的Socket原语如下:
- recvfrom():从绑定的地址接收数据
- sendto():向指定的地址发送数据,在调用的参数中应该传入通信对端的地址和端口
UDP-Serverse.py:
'''UDP-Socket服务器端'''
import socket
HOST = '0.0.0.0' #IP
PORT = 3434 #端口
#AF_INET说明使用IPv4地址,SOCK_DGRAM指明UDP
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.bind((HOST,PORT)) #绑定IP与端口
while True:
data,addr = s.recvfrom(1024) #本次接收最大数据长度为1024
print('Receiverd:%s from %s' % (data,str(addr)))
s.close()
UDP-Client.py:
'''UDP-Socket客户端'''
import socket
import os
HOST = '127.0.0.1'
PORT = 3434
#AF_INET说明使用IPv4地址,SOCK_DGRAM指明UDP协议
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
data = 'Hello UDP!!!'
data_change = bytes(data,encoding='utf-8')
s.sendto(data_change,(HOST,PORT))
print('Sent:%s to %s:%d'%(data,HOST,PORT))
s.close() #关闭连接
os.system('pause') #暂停程序,避免直接结束,看不到结果
效果图:
注意:先运行服务器端代码UDP-Serverse.py:,再运行客户端代码UDP-Client.py
客户端直接调用sendto()向指定的地址发送数据
客户端端口63140由客户端程序在调用sendto()时自动生成