TCP协议:
- 提到TCP,就会有其显著的特点:三次握手 全双工
- 其三次握手的具体内容形象的一个说法就像两个很客气的人加完了好友之后的反应:
- A: 我可以加你为好友吗?
- B:可以呀,我可以加你为好友吗?
- A:可以呀
然后就开始没羞没臊的聊天。
(我记得11-12年那会的QQ确实是这样,双方都有选择是否加对方为好友的选项)
在添加好友之后客户端和服务器之间进行的消息交互是全双工的,有发送有应答
(如果有发送没有应答会怎么样?如果程序设置成没有应答也是没问题的,但是这样就不是TCP的协议了啊!)
客户端流程:
1.创建socket
2.链接服务器
3.接收数据
4.关闭套接字
代码:
import socket
def main():
#pass
#1.创建套接字 AF_INET 为ipv4 SOCK_STREAM为流控,选择TCP选择的协议
tcp_client = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
server_ip = '192.168.152.1'
server_port = 7891
#2.连接服务器
tcp_client.connect((server_ip,server_port))
while True:
#3.收发
send_content = input('请输入要发送的内容:')
tcp_client.send(send_content.encode('gbk'))
recv_content = tcp_client.recv(1024)
#print(recv_content.encode())
print(recv_content.decode('gbk'))
#4.关闭 但是此时这个代码执行不到,
tcp_client.close()
if __name__ == '__main__':
main()
服务器端流程:
1.socket创建套接字
2.bind绑定IP和port
3.listen使套接字变为可以被动连接
4.accept等待客户端的连接
5.recv/send接收发送数据
代码:
import socket
def main():
#1.创建套接字 AF_INET 为ipv4 SOCK_STREAM为流控,选择TCP选择的协议
tcp_server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
#2.绑定端口号和IP
tcp_server.bind(('', 7891))
#3.listen使套接字变为可以被动连接
tcp_server.listen(128)
while True:
#4.accept等待客户端的连接 阻塞在此阶段,三次握手是在此阶段,在三次握手完成后开始下面的通讯
new_server_socket, client_addr = tcp_server.accept()
print(client_addr)
while True:
#完成收
recv_content = new_server_socket.recv(1024)
print(recv_content.decode('gbk'))
#如果用网络调试助手进行测试,令调试助手为客户端模式,可以同时打开多个调试口
# 此时只要关闭一个程序,下一个程序即可与服务器通讯
if recv_content.decode('gbk'):
#应答
send_content = 'hello'
new_server_socket.send(send_content.encode('gbk'))
#发出消息和应答就体现在此处
#pass
else:
#new_server_socket.close()
break
new_server_socket.close()
#tcp_server.close()
if __name__ == '__main__':
main()
至此,第一步不带多线程的TCP通讯完成了,
后续会进行多线程的操作
升级程序:
之前课堂上讲解时,使用netassist模拟client,在server中判断如果收到的信息帧长度为0就断开通讯,那么我们在程序中如何模拟发送长度为0的信息帧呢?一样,只要发出一个空的字符串(并非空格)就可以了,不过在server中通过break跳出内循环就结束了这个通讯了。在复杂的程序中可能遇到其他内容导致server异常结束,我以为是方式不对呢。不过吧,写程序写多了就好了,把那些容易出问题的地方通过抛异常的方式就解决了,try真是个神器
程序如下:
client:
设置发送5次正常字符,第6次发空
import socket
def main():
#pass
#1.创建套接字 AF_INET 为ipv4 SOCK_STREAM为流控,选择TCP选择的协议
tcp_client = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
server_ip = '192.168.18.6'
server_port = 7891
#2.连接服务器
tcp_client.connect((server_ip,server_port))
m = 0
while m <5:
#3.收发
send_content = 'mh' #input('请输入要发送的内容:')
tcp_client.send(send_content.encode('gbk'))
recv_content = tcp_client.recv(1024)
#print(recv_content.encode())
print(recv_content.decode('gbk'))
m += 1
else:
send_content = ''
tcp_client.send(send_content.encode('gbk'))
#4.关闭 但是此时这个代码执行不到,
tcp_client.close()
if __name__ == '__main__':
main()
server 其实并没有变 可以用之前的
import socket
def main():
#1.创建套接字 AF_INET 为ipv4 SOCK_STREAM为流控,选择TCP选择的协议
tcp_server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
#2.绑定端口号和IP
tcp_server.bind(('', 7891))
#3.listen使套接字变为可以被动连接
tcp_server.listen(128)
while True:
#4.accept等待客户端的连接 阻塞在此阶段,三次握手是在此阶段,在三次握手完成后开始下面的通讯
new_server_socket, client_addr = tcp_server.accept()
print(client_addr)
while True:
#完成收
recv_content = new_server_socket.recv(1024)
print(recv_content.decode('gbk'))
#如果用网络调试助手进行测试,令调试助手为客户端模式,可以同时打开多个调试口
# 此时只要关闭一个程序,下一个程序即可与服务器通讯
if recv_content.decode('gbk'):
#应答
send_content = 'hello'
new_server_socket.send(send_content.encode('gbk'))
#发出消息和应答就体现在此处
#pass
else:
#new_server_socket.close()
break
new_server_socket.close()
#tcp_server.close()
if __name__ == '__main__':
main()