网络编程[第一篇]基于tcp协议的套接字编程
将服务端-客户端的连接比作双方打电话的过程
2019-07-24
一.客户端
主动的一方:
客户端实例化一个socket对象--> 主动像服务端发送连接请求--> (服务端接受请求后即可进行数据传输--> )请求成功后发送信息--> (服务端收到数据信息后反馈一个数据信息给客户端,确认操作成功--> )关闭进程
####
——手机通话过程
买手机——>打电话——>说话(发信息)——>听对面说话(收信息)——>沟通完成后挂电话
import socket #买手机 -- 套接字家族 | 端口协议 phone = socket.socket(socket.af_inet,socket.sock_stream) #直接打电话 连接服务端 -- 给一个地址- ip | 端口号 phone.connect(('127.0.0.1',1000)) #接通电话后发信息 phone.send('hello'.encode('utf-8')) #接收反馈信息 指定一次接收的量 data = phone.recv(100) print('信息为: ',data) #关机 phone.close()
二.服务端
被动的一方:
实例化一个socket对象--> *设置一个监听地址(提供一台电脑的唯一标识—ip+端口号)*-->*设置最大监听数量*-->
接受客户端来的一个连接请求--> 连接成功后接收客户端发来的信息--> 发送反馈信息给客户端--> 关闭该连接请求(可能不止一个连接请求)--> 没有连接请求后关闭进程
####
——手机通话过程
买电话——>*买一张电话卡(唯一一台设备)【提供给客户端一个地址来连接服务端】*——>*开机(处于监听状态,有一个最大监听数量)*——>
接一个电话——>接收到对方的信息——>回复一个信息——>打完电话后挂断电话——>关机(不再监听)
import socket #买手机 -- 套接字家族 | 端口协议 phone = socket.socket(socket.af_inet,socket.sock_stream) #买电话卡 -- 监听一个地址- ip | 端口号 phone.bind(('127.0.0.1',1000)) #开机 指定监听的最大数量 **backlog -- 半连接池**所有的电话均在其中等待 phone.listen(5) #等电话-接电话 电话接通后会得到(sock--一个socket对象, addr--客户端地址) #socket对象 | 客户端地址 link, addr = phone.accept() # **从backlog中拿出一个电话接通**
#print('socket对象为:',link) #print('客户端地址为:',addr)
#》》》
#socket对象为: <socket.socket fd=628, family=addressfamily.af_inet, type=socketkind.sock_stream, proto=0, laddr=('127.0.0.1', 1000), raddr=('127.0.0.1', 64538)>
#客户端地址为: ('127.0.0.1', 64538)
#电话接通后接收信息 指定一次接收信息的数量 data = link.recv(100) print('信息为: ',data) #接收到信息后,反馈给client端一个信息,以告诉他已成功接收 link.send(data) #完成一切操作后关掉link,再关机 link.close() phone.close()
上述代码互相接发一次,需改进实现多次接发信息
并且只连接一次客户端,对于半连接池中的连接请求信息不再同意连接,这个问题同样需要解决
三.优化——多次接发信息以及多次连接用户
客户端:
import socket #买手机 -- 套接字家族 | 端口协议 phone = socket.socket(socket.af_inet,socket.sock_stream) #直接打电话 连接服务端 -- 给一个地址- ip | 端口号 phone.connect(('127.0.0.1',1001)) #实现多次发送信息 while true: #自定义一条信息 msg = input('输入一条信息:') #若信息为空,会导致程序卡死,用if判断跳过此情况 if not msg: continue # 接通电话后发信息 phone.send(msg.encode('utf-8')) print('向服务端发送信息:',msg) # #接收完整信息 # accept = 0 # server_accept = len(msg) #接收反馈信息 指定一次接收的量 data = phone.recv(10) print('成功接收到服务端反馈信息 ') #关机 phone.close()
服务端:
import socket #买手机 -- 套接字家族 | 端口协议 phone = socket.socket(socket.af_inet,socket.sock_stream) #买电话卡 -- 监听一个地址- ip | 端口号 phone.bind(('127.0.0.1',1001)) #开机 指定监听的最大数量 **backlog -- 半连接池**所有的电话均在其中等待 phone.listen(5) #使得服务端完成一次连接后可继续和第二人连接,多次accept while true: #等电话-接电话 电话接通后会得到(return sock, addr) accept() -> (socket object, address info) #tcp链接 | 客户端地址? print('等待连接') link, addr = phone.accept() # **从backlog中拿出一个电话接通** #多次接发信息 while true: #当一个客户端完成通信后客户端主动断开时会导致服务器抛出异常 try: #电话接通后接收信息 指定一次接收信息的数量 data = link.recv(10) print('接受到客户端信息为: ',data) #接收到信息后,反馈给client端一个信息,以告诉他已成功接收 link.send(data) print('成功向客户端发送一个反馈信息') except exception: break #完成一切操作后关掉link,再关机 link.close() phone.close()
四.总结——简化
服务端:
1 ss = socket() #创建服务器套接字 2 ss.bind() #把地址绑定到套接字 3 ss.listen() #监听链接 4 inf_loop: #服务器无限循环 5 cs = ss.accept() #接受客户端链接 6 comm_loop: #通讯循环 7 cs.recv()/cs.send() #对话(接收与发送) 8 cs.close() #关闭客户端套接字 9 ss.close() #关闭服务器套接字(可选)
客户端:
1 cs = socket() # 创建客户套接字 2 cs.connect() # 尝试连接服务器 3 comm_loop: # 通讯循环 4 cs.send()/cs.recv() # 对话(发送/接收) 5 cs.close() # 关闭客户套接字
上一篇: django验证码captcha