-
问题描述
个人认为,Socket编程是一个很重要的东西,无论是什么语言,用到Socket编程的一定有很多,所以,学习Socket编程是很重要的。个人学习Socket编程的原因,是因为自己觉得学Python有一段时间了,想要做个桌面应用程序出来,首先要搞定Socket编程,所以就开始学习了。下面介绍一下简单的Socket编程。
-
解决方法
直接上代码,分为两个程序,一个是服务端的程序,用于接收其他的tcp连接,另一个是客户端的程序,用于请求连接。
首先,是服务端的程序:
import socket
HOST = '0.0.0.0'
PORT = 8000
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
while True:
conn, addr = s.accept()
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
print('get data ', data.decode('utf-8'))
这里host写的是0.0.0.0,指的是允许所有的IP进行tcp连接,如果设置为127.0.0.1,则就是本机访问,除了服务器程序运行以外的机器无法进行访问。
port就是指端口,指定tcp通过哪个端口进行连接
接下来就是生成socket对象,这里需要说明的是,有的程序生成socket对象使用的是
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
这个和上面代码中的
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
效果是一样的,问题在于,使用第一个代码时,我们进行完连接以后,需要手动的进行close。
sock.close()
而如果使用with语句,那么我们就不需要自己手动设置close,程序能够帮助我们自动关闭,如果你能理解文件操作里面的open 和 with open,那么我相信你也能理解这里with的意思。
socket.AF_INET 指通过ipv4连接,socket.SOCK_STREAM 指通过tcp连接
s.bind 指将套接字绑定到我们之前指定的地址
s.listen 指开始进行监听tcp连接
接下来进行死循环
conn, addr = s.accept() 接受TCP链接并返回(conn, address),其中conn是新的套接字对象,可以用来接收和发送数据,address是连接客户端的地址。
接下来再次进行死循环,上一次的死循环,能够让我们建立连接以后,发送多次消息,而这一次的死循环,是循环接收数据,因为我们接收数据是
data = conn.recv(1024)
即接收1024字节,所以,如果我们发送的字节超过了1024字节,那么我们就进行下一次循环,继续接收1024字节,就一直死循环,直到所有的字节接受完,然后就 break 退出
conn.sendall(data) 指返回数据给客户端,sendall指一次性发送所有的数据,因为如果我们要发送的数据超过了1024字节,用send方法发送数据的话,一次性是发送不完的,是需要用死循环进行发送的, 但是如果我们用sendall,就不用死循环发送了。需要注意的是,我们收到或者发送的数据是bytes格式的,所以我们在发送数据时,需要用encode,将接收的数据变成字符串时,我们需要用decode。
接下来是客户端程序
import socket
HOST = '192.168.5.135' # 服务器的主机名或者 IP 地址
PORT = 8000 # 服务器使用的端口
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.settimeout(5)
while True:
try:
a = input('please input:')
s.sendall(a.encode('utf-8'))
data = s.recv(1024)
print('Received', data.decode('utf-8'))
except socket.timeout as e:
print('time out')
continue
host指服务器ip
port指服务器端口
使用with 语句创建socket对象
s.connect进行tcp连接
s.settimeout(5)设置超时时间,如果一段5秒以后没有还是没有和服务器进行正常的通信,那么,就抛出socket.timeout异常
接下来进行死循环,我们使用input发送我们想发送的字符串
然后使用sendall进行发送,发送之前使用encode将字符串转为bytes格式
接下来进行recv,接收服务器返回来的数据
打印输入服务器数据
如果我们捕获了socket.timeout异常,则进行下一次的数据发送
下图为客户端程序输出:
下图为服务端程序输出:
至此,简单的tcp程序就完成了
-
总结
有了上面的程序,再进行一点异常的捕获、优化,我们就能够进行相对稳定的tcp连接了, 如果后面有碰到多连接的情况,再进行处理。