简单 C/S

 


一、概述
  • socket:(软件抽象层)

        • 对 TCP/IP 的一种封装,介于用户和底层协议之间
        • 用户不用了解各个协议的使用,只需了解socket
        • 用户将数据发送给socket,socket负责传递给相应的协议通道(IP,TCP,UDP,ICMP),由底层协议去实现具体收发

  • socket 执行流程

      • 注意问题:
        • 此处的建立连接和关闭连接是针对socket的;没有TCP的“三次握手/四次挥手”
        • accept() 、recv() 都是阻塞的方法,在没有收到请求或消息前,会一直处于该状态,而不执行后面的代码
        • 收发消息过程中,需要两端不断进行确认和接收

二、重点
  • 注意:
    • python3.5 以后,只能发字节byte,
    • listen(N) N代表能挂起的连接数,即表示,除了当前处理的会话外,可挂起的连接数。
  • 通讯方式:
    • server:
      • 通过socket 创建sk 对象,使用sk对象 accept() 用户请求;
      • 每个client进来,accept 会返回一个客户端 conn 和addr,此后,使用conn 去和该客户端通讯
    • client:
      • 通过socket创建 sk 对象,使用该sk对象去和服务器端的conn通讯
  • send 空消息:
    • recv() 状态,只有接收到非“空”数据才会认为自己受到数据
      • 若client send() 空消息(即命令行下直接回车),recv不会认为自己受到,即还会一直阻塞
      • 而client send() 完成后,会进入recv() ,等待 server的回应,server却还处于阻塞状态,所以此时会发生“卡住”现象
  • 链路断开方式:
    • 1、异常断开:
      • 两端使用 conn <----> sk 进行通讯;任意一段 stop(ide中 红色按钮),相当于去掉了sk 或者 conn,另一端都会发生异常 (此时,链路已然不存在)
    • 2、正常断开:
      • 捕获指定格式数据:
        • 两端分别捕获 "接受到的/发送出的"   的数据,若数据匹配指定格式数据(exit,logout 等),则主动跳到 close()
      • 监控对端状态改变:
        • 正常情况下,conn <----> sk 两端,一端处于recv 一端处于send;若处于send()状态“由send() 转变为close()” (IDE 中 ctrl +d) ,则recv() 端会收到“空数据”(此时,链路存在,只不过状态发生了改变)
        • 可在server端raise 异常进行捕获处理


二、简单的 C/S:
  • 异常断开(链路破裂)+ 正常断开(捕获指定格式数据)+ 防止send 空消息(导致两端同时处于阻塞状态,client端进行处理)
    • server.py
import socket

# 创建socket实例,并进入accept()
server_ip = ('127.0.0.1', 9999)
sk = socket.socket()
sk.bind(server_ip)
sk.listen(2)
conn, addr = sk.accept()

# 给client的提示消息,只打印一遍,所以放在循环外
welcome_data = bytes('welcome to my server', encoding='utf-8')
conn.send(welcome_data)

while True:
# 链路断开异常
try:
recv_data = conn.recv(1024).decode()
print('from client:{}'.format(recv_data))
# 捕获指定格式数据(exit)
if recv_data == 'exit':
print('client required exit')
break
except Exception as ex:
print(ex, 'sb client go away.....')
break
else:
send_data = bytes(recv_data.upper(), encoding='utf-8')
conn.send(send_data)
conn.close()
    • client.py
import socket

# 创建socket
server_ip = ('127.0.0.1', 9999)
sk = socket.socket()
sk.connect(server_ip)
# 接受提示消息
welcome_data = sk.recv(1024).decode()
print(welcome_data)

while True:
user_inp = input('>>').strip()
send_data = bytes(user_inp, encoding='utf-8')

# 防止send 空消息
if len(user_inp) == 0:
continue     
sk.send(send_data)
# 捕获 exit
if user_inp == 'exit':
break
recv_data = sk.recv(1024).decode()
print(recv_data)
sk.close()
    • 注意问题:
      • send 在 空消息判断之后,因为若是空消息,就不必发给server
      • send 在 exit判断之前,自己发送的exit自己后面可以捕获;但是不发给server,则server没法捕获
  •  持续服务(accept放入while)+异常断开(链路破裂,try)+正常断开(链路状态转变,raise异常)+ 防止send空消息(导致两端同时处于阻塞状态,client端进行处理) //以后均使用这种形式
    • 说明:
      • 链路异常断开:由try处理
      • 链路正常断开:由server处理,server会收到 len(recv) == 0,raise异常后break
        • client执行exit跳到close,
        • client主动执行ctrl+d中断
    • server.py
      • 此时,server 只需要处理链路状态异常(len =0情况)、和链路异常两种情况
import socket

# socket 对象
server_ip = ('127.0.0.1', 9999)
sk = socket.socket()
sk.bind(server_ip)
sk.listen(2)
# 持续 服务
while True:
conn, addr = sk.accept()
welcome_data = bytes('welcome to my server', encoding='utf-8')
conn.send(welcome_data)

while True:
# 链路破裂
try:
recv_data = conn.recv(1024).decode()
print('from client:{}'.format(recv_data))
 # 链路状态转变,raise异常
if len(recv_data) == 0:
raise Exception('链路状态发生改变,client主动进入close()')
send_data = bytes(recv_data.upper(), encoding='utf-8')
conn.send(send_data)
except Exception as ex:
print(ex, 'sb client go away.....')
break

conn.close()
    • client.py
      • 此时,client 不论是 ctrl+d 还是手动 exit,都会进入close(),即转化链路状态
import socket
# 创建socket 对象
server_ip = ('127.0.0.1', 9999)
sk = socket.socket()
sk.connect(server_ip)
# 提示
welcome_data = sk.recv(1024).decode()
print(welcome_data)

while True:
user_inp = input('>>').strip()
# 若输入exit,则跳到close() 进而转换链路状态
if user_inp == 'exit':
break
# 防止send空消息,导致两边都处于 recv 阻塞状态
if len(user_inp) == 0:
continue
send_data = bytes(user_inp, encoding='utf-8')
sk.send(send_data)
recv_data = sk.recv(1024).decode()
print(recv_data)
sk.close()







 

posted on 2016-09-05 14:46  台灯不太亮  阅读(197)  评论(0编辑  收藏  举报

导航