C /S 架构——socke模块
一、socket概念
如果我们需要编写基于网络进行数据交互的程序 意味着我们需要自己通过代码来控制我们之前所学习的OSI七层(很繁琐 很复杂 类似于我们自己编写操作系统)
socket类似于操作系统 封装了丑陋复杂的接口提供简单快捷的接口
socket也叫套接字
基于文件类型的套接字家族(单机)
AF_UNIX
基于网络类型的套接字家族(联网)
AF_INET
1.Socket通信
ocket是应用层与TCP/IP协议簇通信的中间抽象层,是一组接口。在设计模式中其实就是门面模式。Socket将复杂的TCP/IP协议簇隐藏在接口后面,对于用户而言,一组接口即可让Socket去组织数据,以符合指定的协议。
socket 其实就是操作系统提供给程序员操作「网络协议栈」的接口,说人话就是,你能通过socket 的接口,来控制协议找工作,从而实现网络通信,达到跨主机通信。
2.关于套接字socket
所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议栈进行交互的接口
套接字是通信的基石,是支持TCP/IP协议的路通信的基本操作单元。可以将套接字看作不同主机间的进程进行双间通信的端点,它构成了单个主机内及整个网络间的编程界面。套接字存在于通信域中,通信域是为了处理一般的线程通过套接字通信而引进的一种抽象概念。套接字通常和同一个域中的套接字交换数据(数据交换也可能穿越域的界限,但这时一定要执行某种解释程序),各种进程使用这个相同的域互相之间用Internet协议簇来进行通信。
Socket(套接字)可以看成是两个网络应用程序进行通信时,各自通信连接中的端点,这是一个逻辑上的概念。它是网络环境中进程间通信的API(应用程序编程接口),也是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连进程。通信时其中一个网络应用程序将要传输的一段信息写入它所在主机的 Socket中,该 Socket通过与网络接口卡(NIC)相连的传输介质将这段信息送到另外一台主机的 Socket中,使对方能够接收到这段信息。 Socket是由IP地址和端口结合的,提供向应用层进程传送数据包的机制
二、socket代码简介
1.server端
# coding:utf-8
# 导入socket模块
import socket
# 1、产生一个socket对象并指定采用的通信版本喝协议(TCP)
# 括号内不屑参数,默认就是TCP协议、family = AF_INET基于网络的套接字
# type = SOCK_STREAM流式协议即TCP
server = socket.socket()
# 2、绑定一个固定的地址(服务器必备的条件)
# 127.0.0.1为本地回环地址,只有自己的电脑可以访问
# 括号内前面为IP地址、后面为端口号
server.bind(('127.0.0.1', 8080))
# 3、建立半连接池(就是可以规定最大的连接数为多少)
server.listen(8)
# 4、等待接收客户端的数据、地址
# sock双向通道,addr客户端的地址
# return scok、addr 三次握手
sock, addr = server.accept()
# 5、接收客户端发来的数据 括号内表示接收的字节数
date = sock.recv(1024)
# 5.1、对接收来的数据进行解码并输出
print(date.decode('utf-8'))
# 5.2、给客户端发送消息 注意消息必须是bytes类型
sock.send('you are right! i follow you! '.encode('utf-8'))
# 6.关闭双向通道
sock.close()
# 7.关闭服务器
server.close()
2.client端
# coding:utf-8
# 导入socket模块
import socket
# 1.生成socket对象指定类型和协议
client = socket.socket()
# 2.通过服务端的地址链接服务器
client.connect(('127.0.0.1', 8080))
# 3.直接给服务端发送消息
client.send('i have very much money!come on baby!'.encode('utf-8'))
# 4. 接收服务器端发来的消息
data = client.recv(1024)
print(data.decode('utf-8'))
# 5.断开与服务端的链接
client.close()
三、代码优化
1.聊天内容自定义
针对消息采用input获取
2.让聊天循环起来
将聊天的部分用循环包起来
3.用户输入的消息不能为空
本质其实是两边不能都是recv或者send 一定是一方收一方发
4.服务端多次重启可能会报错
Address already in use 主要是mac电脑会报
方式1:改端口号
方式2:博客里面代码拷贝即可
5.当客户端异常断开的情况下 如何让服务端继续服务其他客人
windows服务端会直接报错
mac服务端会有一段时间反复接收空消息延迟报错
异常处理、空消息判断
1.server端
# coding:utf-8
# 导入socket模块
import socket
# 导入
from socket import SO_REUSEADDR, SOL_SOCKET
# 1、产生一个socket对象并指定采用的通信版本喝协议(TCP)
# 括号内不屑参数,默认就是TCP协议、family = AF_INET基于网络的套接字
# type = SOCK_STREAM流式协议即TCP
server = socket.socket()
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
# 2、绑定一个固定的地址(服务器必备的条件)
# 127.0.0.1为本地回环地址,只有自己的电脑可以访问
# 括号内前面为IP地址、后面为端口号
server.bind(('127.0.0.1', 8080))
# 3、建立半连接池(就是可以规定最大的连接数为多少)
server.listen(8)
while True:
# 4、等待接收客户端的数据、地址
# sock双向通道,addr客户端的地址
# return scok、addr 三次握手
try:
sock, addr = server.accept()
except OSError:
break
while True:
try:
# 5、接收客户端发来的数据 括号内表示接收的字节数
date = sock.recv(1024)
# 5.1、对接收来的数据进行解码并输出
print(date.decode('utf-8'))
# 5.2、给客户端发送消息 注意消息必须是bytes类型
msg = input('please input you need sent client message>>>:')
try:
if msg == 'q':
# 6.关闭双向通道
sock.close()
# 7.关闭服务器
server.close()
except OSError:
break
sock.send(msg.encode('utf-8'))
except OSError:
break
2.client端
# coding:utf-8
# 导入socket模块
import socket
# 1.生成socket对象指定类型和协议
client = socket.socket()
# 2.通过服务端的地址链接服务器
client.connect(('127.0.0.1', 8080))
while True:
# 3.直接给服务端发送消息
msg = input('please input you need sent server message>>>:')
try:
if msg == 'q':
# 5.断开与服务端的链接
client.close()
client.send(msg.encode('utf-8'))
except OSError:
break
# 4. 接收服务器端发来的消息
data = client.recv(1024)
print(data.decode('utf-8'))
四、报错处理
报错信息:
[WinError 10061] 由于目标计算机积极拒绝,无法连接。
解决办法:
1.按住开始键+r,输入regedit,打开注册表
2.然后在计算\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings下面找到ProxyEnable将十六进制的值改为1
解决问题
TypeError: a bytes-like object is required, not 'str'
解决思路
问题出在python3.5和Python2.7在套接字返回值解码上有区别:
python bytes和str两种类型可以通过函数encode()和decode()相互转换,
str→bytes:encode()方法。str通过encode()方法可以转换为bytes。
bytes→str:decode()方法。如果我们从网络或磁盘上读取了字节流,那么读到的数据就是bytes。要把bytes变为str,就需要用decode()方法。
TCP端口复用引发的异常,用setsockopt来解决
我们在并发连接一个服务端时候他会出现这种情况
OSError: [WinError 10048] 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。假如端口被socket使用过,并且利用socket.close()来关闭连接,但此时端口还没有释放,要经过一个TIME_WAIT的过程之后才能使用,这是TNN的相当烦银的,为了实现端口的马上复用,可以选择setsockopt()函数来达到.端口复用的实现,我在这里用Python举个TCP端口复用的例子,UDP套接字要做的完全一样。我们可以在定义好的端口加这句
from socket import
server = socket()
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
server.bind(('127.0.0.1', 8000))
server.listen(5)
五、半连接池的概念
server.listen(5) # 半连接池
当有多个客户端来链接的情况下 我们可以设置等待数量(不考虑并发问题)
假设服务端只有一个人的情况下
在测试半连接池的时候 可以不用input获取消息 直接把消息写死即可
标签:架构,socket,server,client,模块,socke,utf,接字,服务端
From: https://www.cnblogs.com/HaiMan/p/16897099.html