常用的套接字有两种tcp和udp
-
tcp跟打电话类似,客户端向服务器发送消息时首先要建立连接(即服务器只有接起电话的过程)* 后,两者才能交流,同时交流的时候能确保每一条消息都能传送给对方。
-
udp则类似邮政服务,客户端不用查询服务器的状态,直接发送消息(快件)即可,客户端不管服务器是否接受到该快件,这样做的好处是更加快速
实验
1、tcp
1.1 服务器端(server.py)
from socket import *
from time import ctime
HOST = '' ## 默认为本机IP地址
PORT = 21567 ## 端口号
BUFSIZE = 1024 ## 每次传送1MB
ADDR = (HOST, PORT)
"""
socket第一个参数AF_INETb时IPV4, 如果时IPV6,则使用AF_INET6, 第二个参数SOCK_STREAM表示TCP协议,
如果是UDP,则使用SOCK_DGRAM
"""
from socket import *
from time import ctime
HOST = ''
PORT = 21567 ## 端口号
BUFSIZE = 1024 ## 每次传送1MB
ADDR = (HOST, PORT)
"""
socket第一个参数AF_INETb时IPV4, 如果时IPV6,则使用AF_INET6, 第二个参数SOCK_STREAM表示TCP协议,
如果是UDP,则使用SOCK_DGRAM
"""
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR) ## 将端口绑定到socket上
tcpSerSock.listen(5) ## 设置socket最大同时连接数为5
while True:
print("waiting for connection...")
tcpCliSock, addr = tcpSerSock.accept() ## 等待客户端连接 (联想到操作系统的进程等待)
print("... connected from:", addr)
## 客户端连接成功进入无限循环(联想到操作系统的进程唤醒)
while True:
data = tcpCliSock.recv(BUFSIZE) ## 接受客户端消息
if not data:
break
tcpCliSock.send(bytes('[%s] %s' % (ctime(), ctime()), "utf-8")) ##向客户端返回时间消息
tcpCliSock.close()
tcpSerSock.close() ## 关闭socket
1.2 客户机端(client.py)
from socket import *
HOST = '127.0.0.1'
PORT = 21567 ## 端口号
BUFSIZE = 1024 ## 每次传送1MB
ADDR = (HOST, PORT)
tcpCliSock = socket(AF_INET, SOCK_STREAM) ## 创建SOCKET
tcpCliSock.connect(ADDR) ## 连接客户端
while True:
data = input('> ') ## 待发送信息
if not data:
break
tcpCliSock.send(bytes(data, encoding='utf-8')) ## 发送信息
data = tcpCliSock.recv(BUFSIZE) ## 接受信息
if not data:
break
print(data.decode('utf-8')) ## 用utf-8解码接受到的字节流
tcpCliSock.close() ## 关闭socket
1.3 运行结果
可以看到客户端只和服务器连接了一次,即建立连接之后就可以一直发送消息了。
1.4 注意点
由于python3的问题,在接受和发送的时候只能传输字节流数据,因此在需要将字符串转成bytes才能正常运行!!!
1.5 进一步思考
其实示例代码并不是完全没有问题的,假设存在这样一i中可能,有服务器为A, 客户端B和C, B与A建立连接后, C不能与A建立连接,说好的最大连接数呢,C只有在B与A通话结束后才能建立连接并通话,下一步就是要解决这个问题。
(请参考python多线程)
2、 udp
2.1 服务器(server.py)
from socket import *
from time import ctime
HOST = ''
PORT = 21567 ## 端口号
BUFSIZE = 1024 ## 每次传送1MB
ADDR = (HOST, PORT)
"""
socket第一个参数AF_INETb时IPV4, 如果时IPV6,则使用AF_INET6, 第二个参数SOCK_STREAM表示TCP协议,
如果是UDP,则使用SOCK_DGRAM
"""
udpSerSock = socket(AF_INET, SOCK_DGRAM)
udpSerSock.bind(ADDR) ## 将端口绑定到socket上
## udp套接字没有最大连接数这一个参数
while True:
print("waiting for message...")
data, addr = udpSerSock.recvfrom(BUFSIZE) ##无需连接,直接接受消息
udpSerSock.sendto(bytes('[%s] %s' % (ctime(), data), "utf-8"), addr) ## 返回消息
print("... received from and return to:", addr)
udpSerSock.close() ## 关闭socket
2.2 客户端(client.py)
from socket import *
HOST = '127.0.0.1'
PORT = 21567 ## 端口号
BUFSIZE = 1024 ## 每次传送1MB
ADDR = (HOST, PORT)
udpCliSock = socket(AF_INET, SOCK_DGRAM) ## 创建SOCKET
## 无需连接服务器端
while True:
data = input('> ') ## 待发送信息
if not data:
break
udpCliSock.sendto(bytes(data, encoding='utf-8'), ADDR) ## 发送信息
data, ADDR = udpCliSock.recvfrom(BUFSIZE) ## 接受信息
if not data:
break
print(data.decode('utf-8')) ## 用utf-8解码接受到的字节流
udpCliSock.close() ## 关闭socket
2.3 运行截图
udp服务器没有连接数量的限制