加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

python - 网络编程

发布时间:2020-12-17 00:02:39 所属栏目:Python 来源:网络整理
导读:一,引入 你现在已经学会了写python代码,假如你写了两个python文件a.py和b.py,分别去运行,你就会发现,这两个python的文件分别运行的很好。但是如果这两个程序之间想要传递一个数据,你要怎么做呢? 这个问题以你现在的知识就可以解决了,我们可以创建一个

一,引入

你现在已经学会了写python代码,假如你写了两个python文件a.py和b.py,分别去运行,你就会发现,这两个python的文件分别运行的很好。但是如果这两个程序之间想要传递一个数据,你要怎么做呢?

这个问题以你现在的知识就可以解决了,我们可以创建一个文件,把a.py想要传递的内容写到文件中,然后b.py从这个文件中读取内容就可以了。

但是当你的a.py和b.py分别在不同电脑上的时候,你要怎么办呢?

类似的机制有计算机网盘,qq等等。我们可以在我们的电脑上和别人聊天,可以在自己的电脑上向网盘中上传、下载内容。这些都是两个程序在通信。

二,软件开发的架构

我们了解的涉及到两个程序之间通讯的应用大致可以分为两种:

第一种是应用类:qq、微信、网盘、优酷这一类是属于需要安装的桌面应用

第二种是web类:比如百度、知乎、博客园等使用浏览器访问就可以直接使用的应用

这些应用的本质其实都是两个程序之间的通讯。而这两个分类又对应了两个软件开发的架构~

1,C/S 架构

C/S即:Client与Server ,中文意思:客户端与服务器端架构,这种架构也是从用户层面(也可以是物理层面)来划分的。

这里的客户端一般泛指客户端应用程序EXE,程序需要先安装后,才能运行在用户的电脑上,对用户的电脑操作系统环境依赖较大。

?2,B/S 架构

B/S即:Browser与Server,中文意思:浏览器端与服务器端架构,这种架构是从用户层面来划分的。

Browser浏览器,其实也是一种Client客户端,只是这个客户端不需要大家去安装什么应用程序,只需在浏览器上通过HTTP请求服务器端相关的资源(网页资源),客户端Browser浏览器就能进行增删改查。

三,网络基础

1,一个程序如何在网络上找到另一个程序?

首先,程序必须要启动,其次,必须有这台机器的地址,我们都知道我们人的地址大概就是国家省市区街道楼门牌号这样字。那么每一台联网的机器在网络上也有自己的地址,它的地址是怎么表示的呢?

就是使用一串数字来表示的,例如:100.4.5.6

IP地址是指互联网协议地址(英语:Internet Protocol Address,又译为网际协议地址),是IP Address的缩写。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。

IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节)。IP地址通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数。例:点分十进IP地址(100.4.5.6),实际上是32位二进制数(01100100.00000100.00000101.00000110<span style="color: #000000;">)。

什么是端口?

<span style="color: #800000;">"<span style="color: #800000;">端口<span style="color: #800000;">"是英文port的意译,可以认为是设备与外界通讯交流的出口。

因此ip地址精确到具体的一台电脑,而端口精确到具体的程序。

2,osi七层模型

人们按照分工不同把互联网协议从逻辑上划分了层级:

<div class="cnblogs_code" onclick="cnblogs_code_show('69714ff2-47cb-449b-8f8a-b408d0f95f83')">
<img id="code_img_closed_69714ff2-47cb-449b-8f8a-b408d0f95f83" class="code_img_closed" src="https://www.52php.cn/res/2019/02-14/22/1c53668bcee393edac0d7b3b3daff1ae.gif" alt=""><img id="code_img_opened_69714ff2-47cb-449b-8f8a-b408d0f95f83" class="code_img_opened" style="display: none;" onclick="cnblogs_code_hide('69714ff2-47cb-449b-8f8a-b408d0f95f83',event)" src="https://www.52php.cn/res/2019/02-14/22/405b18b4b6584ae338e0f6ecaf736533.gif" alt=""><div id="cnblogs_code_open_69714ff2-47cb-449b-8f8a-b408d0f95f83" class="cnblogs_code_hide">

一,面向连接的传输服务 —-1<span style="color: #000000;">,传输特征:
可靠的数据传输
可靠性指数据传输中 无失序 无差错 无丢失 无重复
所有消息传输前一定会建立连接,传输后一定会断开连接

2<span style="color: #000000;">,三次握手: 在进行面向连接的数据传输前进行传输连接的过程
客户端向服务器发送连接请求(问是否可以连接)
服务器接收到连接请求进行确认,返回报文
客户端收到回复,进行连接建立

3<span style="color: #000000;">,四次挥手: 在进行面向连接的数据传输时,断开连接的过程
主动方发送报文 告知被动方要断开连接
被动方返回报文,告知收到请求,准备断开
被动方再次发送报文给主动方,告知准备完毕可以断开
主动方发送报文进行断开

4<span style="color: #000000;">,应用情况 :适用于传输较大的内容或文件,网络情况良好,需要保证传输可靠性的情况
比如 : 聊天信息,文件的上传下载,邮件传输,网页获取

二,面向无连接的传输服务 —》 udp协议

三,传输特点:

1<span style="color: #000000;">,不保证可靠的数据传输
2<span style="color: #000000;">,没有连接过程
3<span style="color: #000000;">,数据的收发都比较自由,不会受另一端制约
4<span style="color: #000000;">,适用情况: 网络情况较差,对传输可靠情形要求不高。需要提升传输效率的情况
比如 : 网络视频,群聊,发送广播

3,socket 概念

socket层

理解socket

Socket是应用层与

+

4,套接字 (socket) 的发展史

起源 :?套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。?

基于文件类型的套接字家族

套接字家族的名字:AF_UNIX

unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

基于网络类型的套接字家族

套接字家族的名字:AF_INET

(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)

?5,tcp协议和udp协议

TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;电子邮件、文件传输程序。

UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统?(DNS);视频流;IP语音(VoIP)。

先上个图:

<div class="cnblogs_code" onclick="cnblogs_code_show('6efe2f13-ab2f-4f7d-a0f9-52509a070b9b')">
<img id="code_img_closed_6efe2f13-ab2f-4f7d-a0f9-52509a070b9b" class="code_img_closed" src="https://www.52php.cn/res/2019/02-14/22/1c53668bcee393edac0d7b3b3daff1ae.gif" alt=""><img id="code_img_opened_6efe2f13-ab2f-4f7d-a0f9-52509a070b9b" class="code_img_opened" style="display: none;" onclick="cnblogs_code_hide('6efe2f13-ab2f-4f7d-a0f9-52509a070b9b',event)" src="https://www.52php.cn/res/2019/02-14/22/405b18b4b6584ae338e0f6ecaf736533.gif" alt=""><div id="cnblogs_code_open_6efe2f13-ab2f-4f7d-a0f9-52509a070b9b" class="cnblogs_code_hide">

1234<span style="color: #000000;">,绑定地址(IP 端口号)

</span>1<span style="color: #000000;"&gt;,格式: 
   sockfd.bind()
</span>2<span style="color: #000000;"&gt;,功能 : 绑定地址
</span>3<span style="color: #000000;"&gt;,参数 : 一个元组包含两项 
   第一项为IP第二项为端口号 
   (’</span>172.60.50.50’,8888<span style="color: #000000;"&gt;)

5<span style="color: #000000;">,将套接字设置可监听

格式:sockfd.listen(n)
功能 : 将套接字设置为监听套接字
参数 : n是一个正整数 表示监听等待队列的大小

6<span style="color: #000000;">,等待接收连接请求

格式:connfd,addr </span>=<span style="color: #000000;"&gt; sockfd.accept()
功能: 阻塞等待处理客户端连接
返回值 : 第一个 : 一个新的套接字用来和客户端通 信 
第二个 : 连接的客户端的地址
阻塞函数:程序运行到阻塞函数的位置,如果某种期待条件没有达成则暂停继续运行。                       当条件达成后会结束阻塞继续运行。

7<span style="color: #000000;">,收发消息

收消息 
    格式:data </span>=<span style="color: #000000;"&gt; connfd.recv(buffersize)
    功能 : 流式套接字接收消息
    参数 : 一次最多接收多大的消息 字节
    返回值 : 返回接收到的内容
发消息 
    格式:n </span>=<span style="color: #000000;"&gt; connfd.send(data)
    功能 : 流式套接字发送消息
    参数 : 要发送的内容 要求bytes格式
   返回值 : 返回实际发送的字节数

8<span style="color: #000000;">,关闭套接字

格式:close()
功能:关闭套接字 tcp套接字连接断开                                                              </span></pre>
12格式: connect() 功能: 发起连接请求 参数: 是一个元组,表示服务器的地址

3<span style="color: #000000;">,消息收发
recv() send()

4<span style="color: #000000;">,关闭套接字
close()
5<span style="color: #000000;">,recv() 特性
如果连接双方断开连接,则recv会立即结束阻塞返回空字符串
当接收缓冲区为空的时候会阻塞
如果recv一次接收不完缓存去内容,下一次会继续接收
6<span style="color: #000000;">,send()特性
如果一段不存在,另一端还在试图send操作时会产生BrokenPipeError异常
当发送缓冲区慢的时候会阻塞
7<span style="color: #000000;">,网络收发缓冲区
发送和接收消息均先放到缓冲区中,在进行处理
即 recv和send实际是从缓冲区接收内容,向缓冲区发送消息

四,套接字 (socket) 初使用

1,基于TCP协议的socket

tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端

=,8898)) sk.listen() conn,addr = sk.accept() ret = conn.recv(1024) (ret) conn.send(b) conn.close() sk.close()
= socket.socket() sk.connect((,8898)) sk.send(b= sk.recv(1024)

问题 : 有的人在重启服务端时可能会遇到

OSError: [WinError 10048] 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
socket =1) sk.bind((,addr = sk.accept() ret = conn.recv(1024) (ret) conn.send(b) conn.close() sk.close()

2,基于UDP协议的socket

udp是无链接的,启动服务之后可以直接接收消息,不需要提前建立链接

1,简单使用

= socket.socket(type=socket.SOCK_DGRAM) udp_sk.bind((,9000)) msg,addr = udp_sk.recvfrom(1024,addr) udp_sk.close()
=(,9000=socket.socket(type==udp_sk.recvfrom(1024(back_msg.decode(),addr)

2,QQ聊天

=(,8081=socket.socket(type =<span style="color: #0000ff;">while<span style="color: #000000;"> True:
qq_msg,addr
=udp_server_sock.recvfrom(1024<span style="color: #000000;">)
<span style="color: #0000ff;">print
(<span style="color: #800000;">'
<span style="color: #800000;">来自[%s:%s]的一条消息:33[1;44m%s33[0m
<span style="color: #800000;">' %(addr[0],addr[1],qq_msg.decode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'<span style="color: #000000;">)))
back_msg=input(<span style="color: #800000;">'<span style="color: #800000;">回复消息: <span style="color: #800000;">'<span style="color: #000000;">).strip()

udp_server_sock.sendto(back_msg.encode(</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span>),addr)</pre>
=1024=socket.socket(type =qq_name_dic=<span style="color: #000000;">{
<span style="color: #800000;">'
<span style="color: #800000;">悟空
<span style="color: #800000;">':(<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',8081<span style="color: #000000;">),<span style="color: #800000;">'<span style="color: #800000;">哪吒<span style="color: #800000;">':(<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',<span style="color: #800000;">'<span style="color: #800000;">八戒<span style="color: #800000;">':(<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',<span style="color: #800000;">'<span style="color: #800000;">沙僧<span style="color: #800000;">':(<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',}

<span style="color: #0000ff;">while<span style="color: #000000;"> True:
qq_name=input(<span style="color: #800000;">'<span style="color: #800000;">请选择聊天对象: <span style="color: #800000;">'<span style="color: #000000;">).strip()
<span style="color: #0000ff;">while<span style="color: #000000;"> True:
msg=input(<span style="color: #800000;">'<span style="color: #800000;">请输入消息,回车发送,输入q结束和他的聊天: <span style="color: #800000;">'<span style="color: #000000;">).strip()
<span style="color: #0000ff;">if msg == <span style="color: #800000;">'<span style="color: #800000;">q<span style="color: #800000;">':<span style="color: #0000ff;">break
<span style="color: #0000ff;">if <span style="color: #0000ff;">not msg <span style="color: #0000ff;">or <span style="color: #0000ff;">not qq_name <span style="color: #0000ff;">or qq_name <span style="color: #0000ff;">not <span style="color: #0000ff;">in qq_name_dic:<span style="color: #0000ff;">continue<span style="color: #000000;">
udp_client_socket.sendto(msg.encode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'<span style="color: #000000;">),qq_name_dic[qq_name])

    back_msg,addr</span>=<span style="color: #000000;"&gt;udp_client_socket.recvfrom(BUFSIZE)
    </span><span style="color: #0000ff;"&gt;print</span>(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;来自[%s:%s]的一条消息:33[1;44m%s33[0m</span><span style="color: #800000;"&gt;'</span> %(addr[0],back_msg.decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;)))

udp_client_socket.close()

3,时间服务器

socket * time ip_port = (<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',9000<span style="color: #000000;">)
bufsize
= 1024<span style="color: #000000;">

tcp_server =<span style="color: #000000;"> socket(AF_INET,SOCK_DGRAM)
tcp_server.setsockopt(SOL_SOCKET,1<span style="color: #000000;">)
tcp_server.bind(ip_port)

<span style="color: #0000ff;">while<span style="color: #000000;"> True:
msg,addr =<span style="color: #000000;"> tcp_server.recvfrom(bufsize)
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">===><span style="color: #800000;">'<span style="color: #000000;">,msg)

</span><span style="color: #0000ff;"&gt;if</span> <span style="color: #0000ff;"&gt;not</span><span style="color: #000000;"&gt; msg:
    time_fmt </span>= <span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;%Y-%m-%d %X</span><span style="color: #800000;"&gt;'</span>
<span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt;:
    time_fmt </span>= msg.decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;)
back_msg </span>=<span style="color: #000000;"&gt; strftime(time_fmt)

tcp_server.sendto(back_msg.encode(</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;),addr)

tcp_server.close()

socket *=(,9000=1024tcp_client=<span style="color: #000000;">socket(AF_INET,SOCK_DGRAM)

<span style="color: #0000ff;">while<span style="color: #000000;"> True:
msg=input(<span style="color: #800000;">'<span style="color: #800000;">请输入时间格式(例%Y %m %d)>>: <span style="color: #800000;">'<span style="color: #000000;">).strip()
tcp_client.sendto(msg.encode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'<span style="color: #000000;">),ip_port)

data</span>=tcp_client.recv(bufsize)</pre>

3,socket 参数的详解

socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)

创建socket对象的参数说明 :

family</tr>
<tr>
<td>type</td>
<td>
套接字类型应为SOCK_STREAM(默认值),SOCK_DGRAM,SOCK_RAW或其他SOCK_常量之一。SOCK_STREAM?是基于TCP的,有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,多用于资料传送。?SOCK_DGRAM?是基于UDP的,无保障的面向消息的socket,多用于在网络上发广播信息。</td>

</tr>
<tr>
<td>proto</td>
<td>协议号通常为零,可以省略,或者在地址族为AF_CAN的情况下,协议应为CAN_RAW或CAN_BCM之一。</td>

</tr>
<tr>
<td>fileno</td>
<td>如果指定了fileno,则其他参数将被忽略,导致带有指定文件描述符的套接字返回。与socket.fromfd()不同,fileno将返回相同的套接字,而不是重复的。这可能有助于使用socket.close()关闭一个独立的插座。<pre data-source-line="11">
</td>
</tr>

五,黏包

1,黏包现象

让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)

res=subprocess.Popen(cmd.decode(===的结果的编码是以当前所在的系统为准的,如果是windows,那么res.stdout.read()读出的就是GBK编码的,在接收端需要用GBK解码

且只能从管道里读一次结果

同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现就是黏包。

基于tcp协议实现的黏包

socket * ip_port=(<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',8888<span style="color: #000000;">)
BUFSIZE=1024<span style="color: #000000;">

tcp_socket_server=<span style="color: #000000;">socket(AF_INET,SOCK_STREAM)
tcp_socket_server.setsockopt(SOL_SOCKET,1<span style="color: #000000;">)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(5<span style="color: #000000;">)

<span style="color: #0000ff;">while<span style="color: #000000;"> True:
conn,addr=<span style="color: #000000;">tcp_socket_server.accept()
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">客户端<span style="color: #800000;">'<span style="color: #000000;">,addr)

</span><span style="color: #0000ff;"&gt;while</span><span style="color: #000000;"&gt; True:
    cmd</span>=<span style="color: #000000;"&gt;conn.recv(BUFSIZE)
    </span><span style="color: #0000ff;"&gt;if</span> len(cmd) == 0:<span style="color: #0000ff;"&gt;break</span><span style="color: #000000;"&gt;

    res</span>=subprocess.Popen(cmd.decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span>),shell=<span style="color: #000000;"&gt;True,stdout</span>=<span style="color: #000000;"&gt;subprocess.PIPE,stdin</span>=<span style="color: #000000;"&gt;subprocess.PIPE,stderr</span>=<span style="color: #000000;"&gt;subprocess.PIPE)

    stderr</span>=<span style="color: #000000;"&gt;res.stderr.read()
    stdout</span>=<span style="color: #000000;"&gt;res.stdout.read()
    conn.send(stderr)
    conn.send(stdout)</span></pre>
=1024=(,8888s=<span style="color: #000000;">socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res
=<span style="color: #000000;">s.connect_ex(ip_port)

<span style="color: #0000ff;">while<span style="color: #000000;"> True:
msg=input(<span style="color: #800000;">'<span style="color: #800000;">>>: <span style="color: #800000;">'<span style="color: #000000;">).strip()
<span style="color: #0000ff;">if len(msg) == 0:<span style="color: #0000ff;">continue
<span style="color: #0000ff;">if msg == <span style="color: #800000;">'<span style="color: #800000;">quit<span style="color: #800000;">':<span style="color: #0000ff;">break<span style="color: #000000;">

s.send(msg.encode(</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;))
act_res</span>=<span style="color: #000000;"&gt;s.recv(BUFSIZE)

</span><span style="color: #0000ff;"&gt;print</span>(act_res.decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span>),end=<span style="color: #800000;"&gt;''</span>)</pre>

基于udp协议实现的黏包

socket * ip_port=(<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',9000<span style="color: #000000;">)
bufsize=1024<span style="color: #000000;">

udp_server=<span style="color: #000000;">socket(AF_INET,SOCK_DGRAM)
udp_server.setsockopt(SOL_SOCKET,1<span style="color: #000000;">)
udp_server.bind(ip_port)

<span style="color: #0000ff;">while<span style="color: #000000;"> True:
<span style="color: #008000;">#<span style="color: #008000;">收消息
cmd,addr=<span style="color: #000000;">udp_server.recvfrom(bufsize)
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">用户命令-----><span style="color: #800000;">'<span style="color: #000000;">,cmd)

</span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;逻辑处理</span>
res=subprocess.Popen(cmd.decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span>),shell=True,stderr=subprocess.PIPE,stdin=subprocess.PIPE,stdout=<span style="color: #000000;"&gt;subprocess.PIPE)
stderr</span>=<span style="color: #000000;"&gt;res.stderr.read()
stdout</span>=<span style="color: #000000;"&gt;res.stdout.read()

</span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;发消息</span>

<span style="color: #000000;"> udp_server.sendto(stderr,addr)
udp_server.sendto(stdout,addr)
udp_server.close()

socket *=(,9000=1024udp_client=<span style="color: #000000;">socket(AF_INET,SOCK_DGRAM)

<span style="color: #0000ff;">while<span style="color: #000000;"> True:
msg=input(<span style="color: #800000;">'<span style="color: #800000;">>>: <span style="color: #800000;">'<span style="color: #000000;">).strip()
udp_client.sendto(msg.encode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'<span style="color: #000000;">),ip_port)
err,addr=<span style="color: #000000;">udp_client.recvfrom(bufsize)
out,addr=<span style="color: #000000;">udp_client.recvfrom(bufsize)
<span style="color: #0000ff;">if<span style="color: #000000;"> err:
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">error : %s<span style="color: #800000;">'%err.decode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'),end=<span style="color: #800000;">''<span style="color: #000000;">)
<span style="color: #0000ff;">if<span style="color: #000000;"> out:
<span style="color: #0000ff;">print(out.decode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'),end=<span style="color: #800000;">'')

注意:只有TCP有粘包现象,UDP永远不会粘包

2,黏包成因

1,TCP协议中的数据传递

tcp协议的拆包机制

面向流的通信特点和Nagle算法

基于tcp协议特点的黏包现象成因

/send的数据为一个消息,需要明白的是当对方send一条信息的时候,无论底层怎样分段分片,TCP协议层会把构成整条消息的数据段排序完成后才呈现在内核缓冲区。

例如基于tcp的套接字客户端往服务端上传文件,发送时文件内容是按照一段一段的字节流发送的,在接收方看了,根本不知道该文件的字节流从何处开始,在何处结束

此外,发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少,通常TCP会根据优化把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。

2,UDP不会发生黏包

补充说明:

用UDP协议发送时,用sendto函数最大能发送数据的长度为:65535- IP头(20) – UDP头(8用TCP协议发送时,由于TCP是数据流协议,因此不存在包大小的限制(暂不考虑缓冲区的大小),这是指在用send函数时,数据长度参数不受限制。而实际上,所指定的这段数据并不一定会一次性发送出去,如果这段数据比较长,会被分段发送,如果比较短,可能会等待和下一次数据一起发送。</span></pre>

3,会发生黏包的两种情况

情况一? 发送方的缓存机制

发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)

socket *=(,8080tcp_socket_server=<span style="color: #000000;">socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(
5<span style="color: #000000;">)

conn,addr=<span style="color: #000000;">tcp_socket_server.accept()

data1=conn.recv(10<span style="color: #000000;">)
data2=conn.recv(10<span style="color: #000000;">)

<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">-----><span style="color: #800000;">',data1.decode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'<span style="color: #000000;">))
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">-----><span style="color: #800000;">',data2.decode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'<span style="color: #000000;">))

conn.close()

=1024=(,8080s=<span style="color: #000000;">socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res
=<span style="color: #000000;">s.connect_ex(ip_port)

s.send(<span style="color: #800000;">'<span style="color: #800000;">hello<span style="color: #800000;">'.encode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'<span style="color: #000000;">))
s.send(<span style="color: #800000;">'<span style="color: #800000;">egg<span style="color: #800000;">'.encode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'))

?情况二? 接收方的缓存机制

接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)?

socket *=(,addr=data1=conn.recv(2) <span style="color: #008000;">#<span style="color: #008000;">一次没有收完整
data2=conn.recv(10)<span style="color: #008000;">#
<span style="color: #008000;">下次收的时候,会先取旧的数据,然后取新的

<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">-----><span style="color: #800000;">',data2.decode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'<span style="color: #000000;">))

conn.close()

=1024=(,socket.SOCK_STREAM) res=s.send(<span style="color: #800000;">'<span style="color: #800000;">hello egg<span style="color: #800000;">'.encode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'))

总结:

黏包现象只发生在tcp协议中:

1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。

2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的

3,黏包的解决方案

解决方案一

问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个死循环接收完所有数据。

=(,8080=1s.bind(ip_port)
s.listen(
5<span style="color: #000000;">)

<span style="color: #0000ff;">while<span style="color: #000000;"> True:
conn,addr=<span style="color: #000000;">s.accept()
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">客户端<span style="color: #800000;">'<span style="color: #000000;">,addr)
<span style="color: #0000ff;">while<span style="color: #000000;"> True:
msg=conn.recv(1024<span style="color: #000000;">)
<span style="color: #0000ff;">if <span style="color: #0000ff;">not msg:<span style="color: #0000ff;">break<span style="color: #000000;">
res=subprocess.Popen(msg.decode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'),
stdin=<span style="color: #000000;">subprocess.PIPE,
stderr=<span style="color: #000000;">subprocess.PIPE,
stdout=<span style="color: #000000;">subprocess.PIPE)
err=<span style="color: #000000;">res.stderr.read()
<span style="color: #0000ff;">if<span style="color: #000000;"> err:
ret=<span style="color: #000000;">err
<span style="color: #0000ff;">else<span style="color: #000000;">:
ret=<span style="color: #000000;">res.stdout.read()
data_length=<span style="color: #000000;">len(ret)
conn.send(str(data_length).encode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'<span style="color: #000000;">))
data=conn.recv(1024).decode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'<span style="color: #000000;">)
<span style="color: #0000ff;">if data == <span style="color: #800000;">'<span style="color: #800000;">recv_ready<span style="color: #800000;">'<span style="color: #000000;">:
conn.sendall(ret)
conn.close()

==s.connect_ex((,8080<span style="color: #0000ff;">while<span style="color: #000000;"> True:
msg
=input(<span style="color: #800000;">'
<span style="color: #800000;">>>:
<span style="color: #800000;">'
<span style="color: #000000;">).strip()
<span style="color: #0000ff;">if len(msg) == 0:<span style="color: #0000ff;">continue
<span style="color: #0000ff;">if msg == <span style="color: #800000;">'<span style="color: #800000;">quit<span style="color: #800000;">':<span style="color: #0000ff;">break<span style="color: #000000;">

s.send(msg.encode(</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;))
length</span>=int(s.recv(1024).decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;))
s.send(</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;recv_ready</span><span style="color: #800000;"&gt;'</span>.encode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;))
send_size</span>=<span style="color: #000000;"&gt;0
recv_size</span>=<span style="color: #000000;"&gt;0
data</span>=b<span style="color: #800000;"&gt;''</span>
<span style="color: #0000ff;"&gt;while</span> recv_size <<span style="color: #000000;"&gt; length:
    data</span>+=s.recv(1024<span style="color: #000000;"&gt;)
    recv_size</span>+=<span style="color: #000000;"&gt;len(data)


</span><span style="color: #0000ff;"&gt;print</span>(data.decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span>))</pre>

解决方案进阶

刚刚的方法,问题在于我们我们在发送

我们可以借助一个模块,这个模块可以把要发送的数据长度转换成固定长度的字节。这样客户端每次接收消息之前只要先接受这个固定长度字节的内容看一看接下来要接收的信息大小,那么最终接受的数据只要达到这个值就停止,就能刚好不多不少的接收完整的数据了。

struct模块

该模块可以把一个类型,如数字,转成固定长度的bytes

>>> struct.pack(,2222222222111struct.error: <span style="color: #800000;">'<span style="color: #800000;">i<span style="color: #800000;">' format requires -2147483648 <= number <= 2147483647 <span style="color: #008000;">#<span style="color: #008000;">这个是范围

<span style="color: #008000;">#<span style="color: #008000;">为避免粘包,必须自定制报头
header={<span style="color: #800000;">'<span style="color: #800000;">file_size<span style="color: #800000;">':1073741824000,<span style="color: #800000;">'<span style="color: #800000;">file_name<span style="color: #800000;">':<span style="color: #800000;">'<span style="color: #800000;">/a/b/c/d/e/a.txt<span style="color: #800000;">',<span style="color: #800000;">'<span style="color: #800000;">md5<span style="color: #800000;">':<span style="color: #800000;">'<span style="color: #800000;">8f6fbf8347faa4924a76856701edb0f3<span style="color: #800000;">'} <span style="color: #008000;">#<span style="color: #008000;">1T数据,文件路径和md5值

<span style="color: #008000;">#<span style="color: #008000;">为了该报头能传送,需要序列化并且转为bytes
head_bytes=bytes(json.dumps(header),encoding=<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">') <span style="color: #008000;">#<span style="color: #008000;">序列化并转成bytes,用于传输

<span style="color: #008000;">#<span style="color: #008000;">为了让客户端知道报头的长度,用struck将报头长度这个数字转成固定长度:4个字节
head_len_bytes=struct.pack(<span style="color: #800000;">'<span style="color: #800000;">i<span style="color: #800000;">',len(head_bytes)) <span style="color: #008000;">#<span style="color: #008000;">这4个字节里只包含了一个数字,该数字是报头的长度

<span style="color: #008000;">#<span style="color: #008000;">客户端开始发送
conn.send(head_len_bytes) <span style="color: #008000;">#<span style="color: #008000;">先发报头的长度,4个bytes
conn.send(head_bytes) <span style="color: #008000;">#<span style="color: #008000;">再发报头的字节格式
conn.sendall(文件内容) <span style="color: #008000;">#<span style="color: #008000;">然后发真实内容的字节格式

<span style="color: #008000;">#<span style="color: #008000;">服务端开始接收
head_len_bytes=s.recv(4) <span style="color: #008000;">#<span style="color: #008000;">先收报头4个bytes,得到报头长度的字节格式
x=struct.unpack(<span style="color: #800000;">'<span style="color: #800000;">i<span style="color: #800000;">',head_len_bytes)[0] <span style="color: #008000;">#<span style="color: #008000;">提取报头的长度
<span style="color: #000000;">
head_bytes=s.recv(x) <span style="color: #008000;">#<span style="color: #008000;">按照报头长度x,收取报头的bytes格式
header=json.loads(json.dumps(header)) <span style="color: #008000;">#<span style="color: #008000;">提取报头

<span style="color: #008000;">#<span style="color: #008000;">最后根据报头的内容提取真实的数据,比如
real_data_len=s.recv(header[<span style="color: #800000;">'<span style="color: #800000;">file_size<span style="color: #800000;">'<span style="color: #000000;">])
s.recv(real_data_len)

values1 = (1,<span style="color: #800000;">'<span style="color: #800000;">abc<span style="color: #800000;">'.encode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'),2.7<span style="color: #000000;">)
values2 = (<span style="color: #800000;">'<span style="color: #800000;">defg<span style="color: #800000;">'.encode(<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'),101<span style="color: #000000;">)
s1 = struct.Struct(<span style="color: #800000;">'<span style="color: #800000;">I3sf<span style="color: #800000;">'<span style="color: #000000;">)
s2 = struct.Struct(<span style="color: #800000;">'<span style="color: #800000;">4sI<span style="color: #800000;">'<span style="color: #000000;">)

<span style="color: #0000ff;">print<span style="color: #000000;">(s1.size,s2.size)
prebuffer=ctypes.create_string_buffer(s1.size+<span style="color: #000000;">s2.size)
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">Before : <span style="color: #800000;">'<span style="color: #000000;">,binascii.hexlify(prebuffer))
<span style="color: #008000;">#<span style="color: #008000;"> t=binascii.hexlify('asdfaf'.encode('utf-8'))<span style="color: #008000;">

<span style="color: #008000;"> print(t)

<span style="color: #000000;">

s1.pack_into(prebuffer,<span style="color: #000000;">values1)
s2.pack_into(prebuffer,s1.size,
<span style="color: #000000;">values2)

<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">After pack<span style="color: #800000;">'<span style="color: #000000;">,binascii.hexlify(prebuffer))
<span style="color: #0000ff;">print<span style="color: #000000;">(s1.unpack_from(prebuffer,0))
<span style="color: #0000ff;">print<span style="color: #000000;">(s2.unpack_from(prebuffer,s1.size))

s3=struct.Struct(<span style="color: #800000;">'<span style="color: #800000;">ii<span style="color: #800000;">'<span style="color: #000000;">)
s3.pack_into(prebuffer,123,123<span style="color: #000000;">)
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">After pack<span style="color: #800000;">'<span style="color: #000000;">,binascii.hexlify(prebuffer))
<span style="color: #0000ff;">print(s3.unpack_from(prebuffer,0))

使用struct解决黏包

借助struct模块,我们知道长度数字可以被转换成一个标准大小的4字节数字。因此可以利用这个特点来预先发送数据长度。

<table style="height: 99px; width: 506px;" border="0">


<tr>
<td>发送时</td>
<td>接收时</td>
</tr>
<tr>
<td>先发送struct转换好的数据长度4字节</td>
<td>先接受4个字节使用struct转换成数字来获取要接收的数据长度</td>
</tr>
<tr>
<td>再发送数据</td>
<td>再按照长度接收数据
</td>

</tr>

=1) ,8080phone.listen(5<span style="color: #000000;">)

<span style="color: #0000ff;">while<span style="color: #000000;"> True:
conn,addr=<span style="color: #000000;">phone.accept()
<span style="color: #0000ff;">while<span style="color: #000000;"> True:
cmd=conn.recv(1024<span style="color: #000000;">)
<span style="color: #0000ff;">if <span style="color: #0000ff;">not cmd:<span style="color: #0000ff;">break
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">cmd: %s<span style="color: #800000;">' %<span style="color: #000000;">cmd)

    res</span>=subprocess.Popen(cmd.decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;),stderr</span>=<span style="color: #000000;"&gt;subprocess.PIPE)
    err</span>=<span style="color: #000000;"&gt;res.stderr.read()
    </span><span style="color: #0000ff;"&gt;print</span><span style="color: #000000;"&gt;(err)
    </span><span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; err:
        back_msg</span>=<span style="color: #000000;"&gt;err
    </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt;:
        back_msg</span>=<span style="color: #000000;"&gt;res.stdout.read()


    conn.send(struct.pack(</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;i</span><span style="color: #800000;"&gt;'</span>,len(back_msg))) <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;先发back_msg的长度</span>
    conn.sendall(back_msg) <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;在发真实的内容</span>

<span style="color: #000000;">
conn.close()

s=<span style="color: #000000;">socket.socket(socket.AF_INET,8080<span style="color: #000000;">))

<span style="color: #0000ff;">while<span style="color: #000000;"> True:
msg=input(<span style="color: #800000;">'<span style="color: #800000;">>>: <span style="color: #800000;">'<span style="color: #000000;">).strip()
<span style="color: #0000ff;">if len(msg) == 0:<span style="color: #0000ff;">continue
<span style="color: #0000ff;">if msg == <span style="color: #800000;">'<span style="color: #800000;">quit<span style="color: #800000;">':<span style="color: #0000ff;">break<span style="color: #000000;">

s.send(msg.encode(</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;))



l</span>=s.recv(4<span style="color: #000000;"&gt;)
x</span>=struct.unpack(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;i</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,l)[0]
</span><span style="color: #0000ff;"&gt;print</span><span style="color: #000000;"&gt;(type(x),x)
</span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; print(struct.unpack('I',l))</span>
r_s=<span style="color: #000000;"&gt;0
data</span>=b<span style="color: #800000;"&gt;''</span>
<span style="color: #0000ff;"&gt;while</span> r_s <<span style="color: #000000;"&gt; x:
    r_d</span>=s.recv(1024<span style="color: #000000;"&gt;)
    data</span>+=<span style="color: #000000;"&gt;r_d
    r_s</span>+=<span style="color: #000000;"&gt;len(r_d)

</span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; print(data.decode('utf-8'))</span>
<span style="color: #0000ff;"&gt;print</span>(data.decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;gbk</span><span style="color: #800000;"&gt;'</span>)) <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;windows默认gbk编码</span></pre>

我们还可以把报头做成字典,字典里包含将要发送的真实数据的详细信息,然后json序列化,然后用struck将序列化后的数据长度打包成4个字节(4个自己足够用了)

==== headers</span>={<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;data_size</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;:len(back_msg)} head_json</span>=<span style="color: #000000;"&gt;json.dumps(headers) head_json_bytes</span>=bytes(head_json,encoding=<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;) conn.send(struct.pack(</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;i</span><span style="color: #800000;"&gt;'</span>,len(head_json_bytes))) <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;先发报头的长度</span> conn.send(head_json_bytes) <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;再发报头</span> conn.sendall(back_msg) <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;在发真实的内容</span>

<span style="color: #000000;">
conn.close()

socket * ip_port=(<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',8080<span style="color: #000000;">)
client=<span style="color: #000000;">socket(AF_INET,SOCK_STREAM)
client.connect(ip_port)

<span style="color: #0000ff;">while<span style="color: #000000;"> True:
cmd=input(<span style="color: #800000;">'<span style="color: #800000;">>>: <span style="color: #800000;">'<span style="color: #000000;">)
<span style="color: #0000ff;">if <span style="color: #0000ff;">not cmd:<span style="color: #0000ff;">continue<span style="color: #000000;">
client.send(bytes(cmd,encoding=<span style="color: #800000;">'<span style="color: #800000;">utf-8<span style="color: #800000;">'<span style="color: #000000;">))

head</span>=client.recv(4<span style="color: #000000;"&gt;)
head_json_len</span>=struct.unpack(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;i</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,head)[0]
head_json</span>=json.loads(client.recv(head_json_len).decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;))
data_len</span>=head_json[<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;data_size</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;]

recv_size</span>=<span style="color: #000000;"&gt;0
recv_data</span>=b<span style="color: #800000;"&gt;''</span>
<span style="color: #0000ff;"&gt;while</span> recv_size <<span style="color: #000000;"&gt; data_len:
    recv_data</span>+=client.recv(1024<span style="color: #000000;"&gt;)
    recv_size</span>+=<span style="color: #000000;"&gt;len(recv_data)

</span><span style="color: #0000ff;"&gt;print</span>(recv_data.decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;))
</span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;print(recv_data.decode('gbk')) #windows默认gbk编码</span></pre>

练习 : 上传下载文件

<span style="color: #0000ff;">class<span style="color: #000000;"> MYTCPServer:
address_family
=<span style="color: #000000;"> socket.AF_INET

socket_type </span>=<span style="color: #000000;"&gt; socket.SOCK_STREAM

allow_reuse_address </span>=<span style="color: #000000;"&gt; False

max_packet_size </span>= 8192<span style="color: #000000;"&gt;

coding</span>=<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;

request_queue_size </span>= 5<span style="color: #000000;"&gt;

server_dir</span>=<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;file_upload</span><span style="color: #800000;"&gt;'</span>

<span style="color: #0000ff;"&gt;def</span> <span style="color: #800080;"&gt;__init__</span>(self,server_address,bind_and_activate=<span style="color: #000000;"&gt;True):
    </span><span style="color: #800000;"&gt;"""</span><span style="color: #800000;"&gt;Constructor.  May be extended,do not override.</span><span style="color: #800000;"&gt;"""</span><span style="color: #000000;"&gt;
    self.server_address</span>=<span style="color: #000000;"&gt;server_address
    self.socket </span>=<span style="color: #000000;"&gt; socket.socket(self.address_family,self.socket_type)
    </span><span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; bind_and_activate:
        </span><span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt;:
            self.server_bind()
            self.server_activate()
        </span><span style="color: #0000ff;"&gt;except</span><span style="color: #000000;"&gt;:
            self.server_close()
            </span><span style="color: #0000ff;"&gt;raise</span>

<span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; server_bind(self):
    </span><span style="color: #800000;"&gt;"""</span><span style="color: #800000;"&gt;Called by constructor to bind the socket.
    </span><span style="color: #800000;"&gt;"""</span>
    <span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; self.allow_reuse_address:
        self.socket.setsockopt(socket.SOL_SOCKET,</span>1<span style="color: #000000;"&gt;)
    self.socket.bind(self.server_address)
    self.server_address </span>=<span style="color: #000000;"&gt; self.socket.getsockname()

</span><span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; server_activate(self):
    </span><span style="color: #800000;"&gt;"""</span><span style="color: #800000;"&gt;Called by constructor to activate the server.
    </span><span style="color: #800000;"&gt;"""</span><span style="color: #000000;"&gt;
    self.socket.listen(self.request_queue_size)

</span><span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; server_close(self):
    </span><span style="color: #800000;"&gt;"""</span><span style="color: #800000;"&gt;Called to clean-up the server.
    </span><span style="color: #800000;"&gt;"""</span><span style="color: #000000;"&gt;
    self.socket.close()

</span><span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; get_request(self):
    </span><span style="color: #800000;"&gt;"""</span><span style="color: #800000;"&gt;Get the request and client address from the socket.
    </span><span style="color: #800000;"&gt;"""</span>
    <span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; self.socket.accept()

</span><span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; close_request(self,request):
    </span><span style="color: #800000;"&gt;"""</span><span style="color: #800000;"&gt;Called to clean up an individual request.</span><span style="color: #800000;"&gt;"""</span><span style="color: #000000;"&gt;
    request.close()

</span><span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; run(self):
    </span><span style="color: #0000ff;"&gt;while</span><span style="color: #000000;"&gt; True:
        self.conn,self.client_addr</span>=<span style="color: #000000;"&gt;self.get_request()
        </span><span style="color: #0000ff;"&gt;print</span>(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;from client </span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,self.client_addr)
        </span><span style="color: #0000ff;"&gt;while</span><span style="color: #000000;"&gt; True:
            </span><span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt;:
                head_struct </span>= self.conn.recv(4<span style="color: #000000;"&gt;)
                </span><span style="color: #0000ff;"&gt;if</span> <span style="color: #0000ff;"&gt;not</span> head_struct:<span style="color: #0000ff;"&gt;break</span><span style="color: #000000;"&gt;

                head_len </span>= struct.unpack(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;i</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,head_struct)[0]
                head_json </span>=<span style="color: #000000;"&gt; self.conn.recv(head_len).decode(self.coding)
                head_dic </span>=<span style="color: #000000;"&gt; json.loads(head_json)

                </span><span style="color: #0000ff;"&gt;print</span><span style="color: #000000;"&gt;(head_dic)
                </span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;head_dic={'cmd':'put','filename':'a.txt','filesize':123123}</span>
                cmd=head_dic[<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;cmd</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;]
                </span><span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; hasattr(self,cmd):
                    func</span>=<span style="color: #000000;"&gt;getattr(self,cmd)
                    func(head_dic)
            </span><span style="color: #0000ff;"&gt;except</span><span style="color: #000000;"&gt; Exception:
                </span><span style="color: #0000ff;"&gt;break</span>

<span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; put(self,args):
    file_path</span>=<span style="color: #000000;"&gt;os.path.normpath(os.path.join(
        self.server_dir,args[</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;filename</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;]
    ))

    filesize</span>=args[<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;filesize</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;]
    recv_size</span>=<span style="color: #000000;"&gt;0
    </span><span style="color: #0000ff;"&gt;print</span>(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;-----></span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,file_path)
    with open(file_path,</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;wb</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;) as f:
        </span><span style="color: #0000ff;"&gt;while</span> recv_size <<span style="color: #000000;"&gt; filesize:
            recv_data</span>=<span style="color: #000000;"&gt;self.conn.recv(self.max_packet_size)
            f.write(recv_data)
            recv_size</span>+=<span style="color: #000000;"&gt;len(recv_data)
            </span><span style="color: #0000ff;"&gt;print</span>(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;recvsize:%s filesize:%s</span><span style="color: #800000;"&gt;'</span> %<span style="color: #000000;"&gt;(recv_size,filesize))

tcpserver1=MYTCPServer((<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',8080<span style="color: #000000;">))

tcpserver1.run()

<span style="color: #008000;">#<span style="color: #008000;">下列代码与本题无关
<span style="color: #0000ff;">class<span style="color: #000000;"> MYUDPServer:

</span><span style="color: #800000;"&gt;"""</span><span style="color: #800000;"&gt;UDP server class.</span><span style="color: #800000;"&gt;"""</span><span style="color: #000000;"&gt;
address_family </span>=<span style="color: #000000;"&gt; socket.AF_INET

socket_type </span>=<span style="color: #000000;"&gt; socket.SOCK_DGRAM

allow_reuse_address </span>=<span style="color: #000000;"&gt; False

max_packet_size </span>= 8192<span style="color: #000000;"&gt;

coding</span>=<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span>

<span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; get_request(self):
    data,client_addr </span>=<span style="color: #000000;"&gt; self.socket.recvfrom(self.max_packet_size)
    </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; (data,self.socket),client_addr

</span><span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; server_activate(self):
    </span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; No need to call listen() for UDP.</span>
    <span style="color: #0000ff;"&gt;pass</span>

<span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; shutdown_request(self,request):
    </span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; No need to shutdown anything.</span>

<span style="color: #000000;"> self.close_request(request)

</span><span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; close_request(self,request):
    </span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; No need to close anything.</span>
    <span style="color: #0000ff;"&gt;pass</span></pre>
<span style="color: #0000ff;">class<span style="color: #000000;"> MYTCPClient:
address_family
=<span style="color: #000000;"> socket.AF_INET

socket_type </span>=<span style="color: #000000;"&gt; socket.SOCK_STREAM

allow_reuse_address </span>=<span style="color: #000000;"&gt; False

max_packet_size </span>= 8192<span style="color: #000000;"&gt;

coding</span>=<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;

request_queue_size </span>= 5

<span style="color: #0000ff;"&gt;def</span> <span style="color: #800080;"&gt;__init__</span>(self,connect=<span style="color: #000000;"&gt;True):
    self.server_address</span>=<span style="color: #000000;"&gt;server_address
    self.socket </span>=<span style="color: #000000;"&gt; socket.socket(self.address_family,self.socket_type)
    </span><span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; connect:
        </span><span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt;:
            self.client_connect()
        </span><span style="color: #0000ff;"&gt;except</span><span style="color: #000000;"&gt;:
            self.client_close()
            </span><span style="color: #0000ff;"&gt;raise</span>

<span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; client_connect(self):
    self.socket.connect(self.server_address)

</span><span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; client_close(self):
    self.socket.close()

</span><span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; run(self):
    </span><span style="color: #0000ff;"&gt;while</span><span style="color: #000000;"&gt; True:
        inp</span>=input(<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;>>: </span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;).strip()
        </span><span style="color: #0000ff;"&gt;if</span> <span style="color: #0000ff;"&gt;not</span> inp:<span style="color: #0000ff;"&gt;continue</span><span style="color: #000000;"&gt;
        l</span>=<span style="color: #000000;"&gt;inp.split()
        cmd</span>=<span style="color: #000000;"&gt;l[0]
        </span><span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; hasattr(self,cmd):
            func</span>=<span style="color: #000000;"&gt;getattr(self,cmd)
            func(l)


</span><span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; put(self,args):
    cmd</span>=<span style="color: #000000;"&gt;args[0]
    filename</span>=args[1<span style="color: #000000;"&gt;]
    </span><span style="color: #0000ff;"&gt;if</span> <span style="color: #0000ff;"&gt;not</span><span style="color: #000000;"&gt; os.path.isfile(filename):
        </span><span style="color: #0000ff;"&gt;print</span>(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;file:%s is not exists</span><span style="color: #800000;"&gt;'</span> %<span style="color: #000000;"&gt;filename)
        </span><span style="color: #0000ff;"&gt;return</span>
    <span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt;:
        filesize</span>=<span style="color: #000000;"&gt;os.path.getsize(filename)

    head_dic</span>={<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;cmd</span><span style="color: #800000;"&gt;'</span>:cmd,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;filename</span><span style="color: #800000;"&gt;'</span>:os.path.basename(filename),<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;filesize</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;:filesize}
    </span><span style="color: #0000ff;"&gt;print</span><span style="color: #000000;"&gt;(head_dic)
    head_json</span>=<span style="color: #000000;"&gt;json.dumps(head_dic)
    head_json_bytes</span>=bytes(head_json,encoding=<span style="color: #000000;"&gt;self.coding)

    head_struct</span>=struct.pack(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;i</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,len(head_json_bytes))
    self.socket.send(head_struct)
    self.socket.send(head_json_bytes)
    send_size</span>=<span style="color: #000000;"&gt;0
    with open(filename,</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;rb</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;) as f:
        </span><span style="color: #0000ff;"&gt;for</span> line <span style="color: #0000ff;"&gt;in</span><span style="color: #000000;"&gt; f:
            self.socket.send(line)
            send_size</span>+=<span style="color: #000000;"&gt;len(line)
            </span><span style="color: #0000ff;"&gt;print</span><span style="color: #000000;"&gt;(send_size)
        </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt;:
            </span><span style="color: #0000ff;"&gt;print</span>(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;upload successful</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;)

client=MYTCPClient((<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',8080<span style="color: #000000;">))

client.run()

六,socket 的更多方法介绍

客户端套接字函数
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

公共用途的套接字函数
s.recv() 接收TCP数据
s.send() 发送TCP数据
s.sendall() 发送TCP数据
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字

面向锁的套接字方法
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间

面向文件的套接字的函数
s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字相关的文件

socket.send(string[,flags])
Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as
<span style="color: #0000ff;">for recv() above. Returns the number of bytes sent. Applications are responsible <span style="color: #0000ff;">for checking that all data has been sent; <span style="color: #0000ff;">if<span style="color: #000000;"> only some of the data was transmitted,the application needs to attempt delivery of the remaining data.

send()的返回值是发送的字节数量,这个数量值可能小于要发送的string的字节数,也就是说可能无法发送string中所有的数据。如果有错误则会抛出异常。

socket.sendall(string[,flags])
Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as <span style="color: #0000ff;">for recv() above. Unlike send(),this method continues to send data <span style="color: #0000ff;">from string until either all data has been sent <span style="color: #0000ff;">or an error occurs. None <span style="color: #0000ff;">is returned on success. On error,an exception <span style="color: #0000ff;">is raised,<span style="color: #0000ff;">and there <span style="color: #0000ff;">is no way to determine how much data,<span style="color: #0000ff;">if<span style="color: #000000;"> any,was successfully sent.

尝试发送string的所有数据,成功则返回None,失败则抛出异常。

故,下面两段代码是等价的:

<span style="color: #008000;">#<span style="color: #008000;">sock.sendall('Hello worldn')

<span style="color: #008000;">#<span style="color: #008000;">buffer = 'Hello worldn'<span style="color: #008000;">

<span style="color: #008000;">while buffer:<span style="color: #008000;">

<span style="color: #008000;"> bytes = sock.send(buffer)<span style="color: #008000;">

<span style="color: #008000;"> buffer = buffer[bytes:]

七,验证客户端链接的合法性

如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac+加盐的方式来实现

socket * secret_key=b<span style="color: #800000;">'<span style="color: #800000;">linhaifeng bang bang bang<span style="color: #800000;">'
<span style="color: #0000ff;">def<span style="color: #000000;"> conn_auth(conn):
<span style="color: #800000;">'''<span style="color: #800000;">
认证客户端链接
:param conn:
:return:
<span style="color: #800000;">'''
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">开始验证新链接的合法性<span style="color: #800000;">'<span style="color: #000000;">)
msg=os.urandom(32<span style="color: #000000;">)
conn.sendall(msg)
h=<span style="color: #000000;">hmac.new(secret_key,msg)
digest=<span style="color: #000000;">h.digest()
respone=<span style="color: #000000;">conn.recv(len(digest))
<span style="color: #0000ff;">return<span style="color: #000000;"> hmac.compare_digest(respone,digest)

<span style="color: #0000ff;">def data_handler(conn,bufsize=1024<span style="color: #000000;">):
<span style="color: #0000ff;">if <span style="color: #0000ff;">not<span style="color: #000000;"> conn_auth(conn):
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">该链接不合法,关闭<span style="color: #800000;">'<span style="color: #000000;">)
conn.close()
<span style="color: #0000ff;">return
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">链接合法,开始通信<span style="color: #800000;">'<span style="color: #000000;">)
<span style="color: #0000ff;">while<span style="color: #000000;"> True:
data=<span style="color: #000000;">conn.recv(bufsize)
<span style="color: #0000ff;">if <span style="color: #0000ff;">not data:<span style="color: #0000ff;">break<span style="color: #000000;">
conn.sendall(data.upper())

<span style="color: #0000ff;">def server_handler(ip_port,bufsize,backlog=5<span style="color: #000000;">):
<span style="color: #800000;">'''<span style="color: #800000;">
只处理链接
:param ip_port:
:return:
<span style="color: #800000;">'''<span style="color: #000000;">
tcp_socket_server=<span style="color: #000000;">socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(backlog)
<span style="color: #0000ff;">while<span style="color: #000000;"> True:
conn,addr=<span style="color: #000000;">tcp_socket_server.accept()
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">新连接[%s:%s]<span style="color: #800000;">' %(addr[0],addr[1<span style="color: #000000;">]))
data_handler(conn,bufsize)

<span style="color: #0000ff;">if <span style="color: #800080;">name == <span style="color: #800000;">'<span style="color: #800000;">main<span style="color: #800000;">'<span style="color: #000000;">:
ip_port=(<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',9999<span style="color: #000000;">)
bufsize=1024<span style="color: #000000;">
server_handler(ip_port,bufsize)

socket * secret_key=b<span style="color: #800000;">'<span style="color: #800000;">linhaifeng bang bang bang<span style="color: #800000;">'
<span style="color: #0000ff;">def<span style="color: #000000;"> conn_auth(conn):
<span style="color: #800000;">'''<span style="color: #800000;">
验证客户端到服务器的链接
:param conn:
:return:
<span style="color: #800000;">'''<span style="color: #000000;">
msg=conn.recv(32<span style="color: #000000;">)
h=<span style="color: #000000;">hmac.new(secret_key,msg)
digest=<span style="color: #000000;">h.digest()
conn.sendall(digest)

<span style="color: #0000ff;">def client_handler(ip_port,bufsize=1024<span style="color: #000000;">):
tcp_socket_client=<span style="color: #000000;">socket(AF_INET,SOCK_STREAM)
tcp_socket_client.connect(ip_port)

conn_auth(tcp_socket_client)

</span><span style="color: #0000ff;"&gt;while</span><span style="color: #000000;"&gt; True:
    data</span>=input(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;>>: </span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;).strip()
    </span><span style="color: #0000ff;"&gt;if</span> <span style="color: #0000ff;"&gt;not</span> data:<span style="color: #0000ff;"&gt;continue</span>
    <span style="color: #0000ff;"&gt;if</span> data == <span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;quit</span><span style="color: #800000;"&gt;'</span>:<span style="color: #0000ff;"&gt;break</span><span style="color: #000000;"&gt;

    tcp_socket_client.sendall(data.encode(</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;))
    respone</span>=<span style="color: #000000;"&gt;tcp_socket_client.recv(bufsize)
    </span><span style="color: #0000ff;"&gt;print</span>(respone.decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;))
tcp_socket_client.close()

<span style="color: #0000ff;">if <span style="color: #800080;">name == <span style="color: #800000;">'<span style="color: #800000;">main<span style="color: #800000;">'<span style="color: #000000;">:
ip_port=(<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',9999<span style="color: #000000;">)
bufsize=1024<span style="color: #000000;">
client_handler(ip_port,bufsize)

socket *

<span style="color: #0000ff;">def client_handler(ip_port,SOCK_STREAM)
tcp_socket_client.connect(ip_port)

</span><span style="color: #0000ff;"&gt;while</span><span style="color: #000000;"&gt; True:
    data</span>=input(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;>>: </span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;).strip()
    </span><span style="color: #0000ff;"&gt;if</span> <span style="color: #0000ff;"&gt;not</span> data:<span style="color: #0000ff;"&gt;continue</span>
    <span style="color: #0000ff;"&gt;if</span> data == <span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;quit</span><span style="color: #800000;"&gt;'</span>:<span style="color: #0000ff;"&gt;break</span><span style="color: #000000;"&gt;

    tcp_socket_client.sendall(data.encode(</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;))
    respone</span>=<span style="color: #000000;"&gt;tcp_socket_client.recv(bufsize)
    </span><span style="color: #0000ff;"&gt;print</span>(respone.decode(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;utf-8</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;))
tcp_socket_client.close()

<span style="color: #0000ff;">if <span style="color: #800080;">name == <span style="color: #800000;">'<span style="color: #800000;">main<span style="color: #800000;">'<span style="color: #000000;">:
ip_port=(<span style="color: #800000;">'<span style="color: #800000;">127.0.0.1<span style="color: #800000;">',bufsize)

socket * secret_key=b<span style="color: #800000;">'<span style="color: #800000;">linhaifeng bang bang bang1111<span style="color: #800000;">'
<span style="color: #0000ff;">def<span style="color: #000000;"> conn_auth(conn):
<span style="color: #800000;">'''<span style="color: #800000;">
验证客户端到服务器的链接
:param conn:
:return:
<span style="color: #800000;">'''<span style="color: #000000;">
msg=conn.recv(32<span style="color: #000000;">)
h=<span style="color: #000000;">hmac.new(secret_key,bufsize)

八,socketserver

= self.request.recv(1024(<span style="color: #0000ff;">if <span style="color: #800080;">name == <span style="color: #800000;">"<span style="color: #800000;">main<span style="color: #800000;">"<span style="color: #000000;">:
HOST,PORT
= <span style="color: #800000;">"
<span style="color: #800000;">127.0.0.1
<span style="color: #800000;">"
,9999

<span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; 设置allow_reuse_address允许服务器重用地址</span>
socketserver.TCPServer.allow_reuse_address =<span style="color: #000000;"&gt; True
</span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; 创建一个server,将服务地址绑定到127.0.0.1:9999</span>
server =<span style="color: #000000;"&gt; socketserver.TCPServer((HOST,PORT),Myserver)
</span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; 让server永远运行下去,除非强制停止程序</span>
server.serve_forever()</pre>
HOST,9999<span style="color: #000000;">
data
= <span style="color: #800000;">"
<span style="color: #800000;">hello<span style="color: #800000;">"

<span style="color: #008000;">#<span style="color: #008000;"> 创建一个socket链接,SOCK_STREAM代表使用TCP协议
<span style="color: #000000;">with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as sock:
sock.connect((HOST,PORT)) <span style="color: #008000;">#<span style="color: #008000;"> 链接到客户端
sock.sendall(bytes(data + <span style="color: #800000;">"<span style="color: #800000;">n<span style="color: #800000;">",<span style="color: #800000;">"<span style="color: #800000;">utf-8<span style="color: #800000;">")) <span style="color: #008000;">#<span style="color: #008000;"> 向服务端发送数据
received = str(sock.recv(1024),<span style="color: #800000;">"<span style="color: #800000;">utf-8<span style="color: #800000;">")<span style="color: #008000;">#<span style="color: #008000;"> 从服务端接收数据

<span style="color: #0000ff;">print(<span style="color: #800000;">"<span style="color: #800000;">Sent: {}<span style="color: #800000;">"<span style="color: #000000;">.format(data))
<span style="color: #0000ff;">print(<span style="color: #800000;">"<span style="color: #800000;">Received: {}<span style="color: #800000;">".format(received))

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!