import socket
'''
socket.socket(socket_family,socket_type,protocal=0)
socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。 获取tcp/ip套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 获取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。
例如tcpSock = socket(AF_INET, SOCK_STREAM)
'''

基于TCP的套接字

tcp服务端

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() #关闭服务器套接字(可选)

tcp客户端

1 cs = socket()    # 创建客户套接字
2 cs.connect() # 尝试连接服务器
3 comm_loop: # 通讯循环
4 cs.send()/cs.recv() # 对话(发送/接收)
5 cs.close() # 关闭客户套接字

socket通信流程与打电话流程类似,我们就以打电话为例来实现一个low版的套接字通信

#_*_coding:utf-8_*_服务端
__author__ = 'Linhaifeng'
import socket
ip_port=('127.0.0.1',9000) #电话卡
BUFSIZE=1024 #收发消息的尺寸
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
s.bind(ip_port) #手机插卡
s.listen(5) #手机待机 conn,addr=s.accept() #手机接电话
# print(conn)
# print(addr)
print('接到来自%s的电话' %addr[0]) msg=conn.recv(BUFSIZE) #听消息,听话
print(msg,type(msg)) conn.send(msg.upper()) #发消息,说话 conn.close() #挂电话 s.close() #手机关机
#_*_coding:utf-8_*_客户端
__author__ = 'Linhaifeng'
import socket
ip_port=('127.0.0.1',9000)
BUFSIZE=1024
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect_ex(ip_port) #拨电话 s.send('linhaifeng nb'.encode('utf-8')) #发消息,说话(只能发送字节类型) feedback=s.recv(BUFSIZE) #收消息,听话
print(feedback.decode('utf-8')) s.close() #挂电话
'''
上述流程的问题是,服务端只能接受一次链接,然后就彻底关闭掉了,实际情况应该是,服务端不断接受链接,然后循环通信,通信完毕后只关闭链接,服务器能够继续接收下一次链接,下面是修改版
'''
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
import socket
ip_port=('127.0.0.1',8081)#电话卡
BUFSIZE=1024
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
s.bind(ip_port) #手机插卡
s.listen(5) #手机待机 while True: #新增接收链接循环,可以不停的接电话
conn,addr=s.accept() #手机接电话
# print(conn)
# print(addr)
print('接到来自%s的电话' %addr[0])
while True: #新增通信循环,可以不断的通信,收发消息
msg=conn.recv(BUFSIZE) #听消息,听话 # if len(msg) == 0:break #如果不加,那么正在链接的客户端突然断开,recv便不再阻塞,死循环发生 print(msg,type(msg)) conn.send(msg.upper()) #发消息,说话 conn.close() #挂电话 s.close() #手机关机 服务端改进版

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
import socket
ip_port=('127.0.0.1',8081)
BUFSIZE=1024
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect_ex(ip_port) #拨电话 while True: #新增通信循环,客户端可以不断发收消息
msg=input('>>: ').strip()
if len(msg) == 0:continue
s.send(msg.encode('utf-8')) #发消息,说话(只能发送字节类型) feedback=s.recv(BUFSIZE) #收消息,听话
print(feedback.decode('utf-8')) s.close() #挂电话 客户端改进版
问题:
有时在重启服务端时可能会遇到

这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址(如果不懂,请深入研究1.tcp三次握手,四次挥手 2.syn洪水攻击 3.服务器高并发情况下会有大量的time_wait状态的优化方法)
解决方法:
#加入一
#调整socket配置,重用ip和端口 phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
phone.bind(('127.0.0.1',8080)) 方法二 发现系统存在大量TIME_WAIT状态的连接,通过调整linux内核参数解决,
vi /etc/sysctl.conf 编辑文件,加入以下内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30 然后执行 /sbin/sysctl -p 让参数生效。 net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭; net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭; net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。 net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间

基于UDP的套接字

udp服务端

1 ss = socket()   #创建一个服务器的套接字
2 ss.bind() #绑定服务器套接字
3 inf_loop: #服务器无限循环
4 cs = ss.recvfrom()/ss.sendto() # 对话(接收与发送)
5 ss.close() # 关闭服务器套接字 udp客户端 cs = socket() # 创建客户套接字
comm_loop: # 通讯循环
cs.sendto()/cs.recvfrom() # 对话(发送/接收)
cs.close() # 关闭客户套接字

udp服务端、客户端

udp套接字简单示例

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
import socket
ip_port=('127.0.0.1',9000)
BUFSIZE=1024
udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) udp_server_client.bind(ip_port) while True:
msg,addr=udp_server_client.recvfrom(BUFSIZE)
print(msg,addr) udp_server_client.sendto(msg.upper(),addr) #_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
import socket
ip_port=('127.0.0.1',9000)
BUFSIZE=1024
udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) while True:
msg=input('>>: ').strip()
if not msg:continue udp_server_client.sendto(msg.encode('utf-8'),ip_port) back_msg,addr=udp_server_client.recvfrom(BUFSIZE)
print(back_msg.decode('utf-8'),addr) qq聊天(由于udp无连接,所以可以同时多个客户端去跟服务端通信)
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
import socket
ip_port=('127.0.0.1',8081)
udp_server_sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #买手机
udp_server_sock.bind(ip_port) while True:
qq_msg,addr=udp_server_sock.recvfrom(1024)
print('来自[%s:%s]的一条消息:\033[1;44m%s\033[0m' %(addr[0],addr[1],qq_msg.decode('utf-8')))
back_msg=input('回复消息: ').strip() udp_server_sock.sendto(back_msg.encode('utf-8'),addr)
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
import socket
BUFSIZE=1024
udp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) qq_name_dic={
'狗哥alex':('127.0.0.1',8081),
'瞎驴':('127.0.0.1',8081),
'一棵树':('127.0.0.1',8081),
'武大郎':('127.0.0.1',8081),
} while True:
qq_name=input('请选择聊天对象: ').strip()
while True:
msg=input('请输入消息,回车发送: ').strip()
if msg == 'quit':break
if not msg or not qq_name or qq_name not in qq_name_dic:continue
udp_client_socket.sendto(msg.encode('utf-8'),qq_name_dic[qq_name]) back_msg,addr=udp_client_socket.recvfrom(BUFSIZE)
print('来自[%s:%s]的一条消息:\033[1;44m%s\033[0m' %(addr[0],addr[1],back_msg.decode('utf-8'))) udp_client_socket.close()
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
import socket
BUFSIZE=1024
udp_client_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) qq_name_dic={
'狗哥alex':('127.0.0.1',8081),
'瞎驴':('127.0.0.1',8081),
'一棵树':('127.0.0.1',8081),
'武大郎':('127.0.0.1',8081),
} while True:
qq_name=input('请选择聊天对象: ').strip()
while True:
msg=input('请输入消息,回车发送: ').strip()
if msg == 'quit':break
if not msg or not qq_name or qq_name not in qq_name_dic:continue
udp_client_socket.sendto(msg.encode('utf-8'),qq_name_dic[qq_name]) back_msg,addr=udp_client_socket.recvfrom(BUFSIZE)
print('来自[%s:%s]的一条消息:\033[1;44m%s\033[0m' %(addr[0],addr[1],back_msg.decode('utf-8'))) udp_client_socket.close()

recv与recvfrom的区别

'''
============part1:须知============ 收发消息的原理须知晓--->请见十一的图:发消息,都是将数据发送到己端的发送缓冲中,收消息都是从己端的缓冲区中收 1. tcp:send发消息,recv收消息 2. udp:sendto发消息,recvfrom收消息 ============part2:send与sendinto============ tcp是基于数据流的,而udp是基于数据报的: send(bytes_data):发送数据流,数据流bytes_data若为空,自己这段的缓冲区也为空,操作系统不会控制tcp协议发空包
sendinto(bytes_data,ip_port):发送数据报,bytes_data为空,还有ip_port,所有即便是发送空的bytes_data,数据报其实也不是空的,自己这端的缓冲区收到内容,操作系统就会控制udp协议发包。
============part3:recv与recvfrom============ 1.tcp协议: (1)如果收消息缓冲区里的数据为空,那么recv就会阻塞(阻塞很简单,就是一直在等着收) (2)只不过tcp协议的客户端send一个空数据就是真的空数据,客户端即使有无穷个send空,也跟没有一个样。 (3)tcp基于链接通信 基于链接,则需要listen(backlog),指定半连接池的大小
基于链接,必须先运行的服务端,然后客户端发起链接请求
对于mac系统:如果一端断开了链接,那另外一端的链接也跟着完蛋recv将不会阻塞,收到的是空(解决方法是:服务端在收消息后加上if判断,空消息就break掉通信循环)
对于windows/linux系统:如果一端断开了链接,那另外一端的链接也跟着完蛋recv将不会阻塞,收到的是空(解决方法是:服务端通信循环内加异常处理,捕捉到异常后就break掉通讯循环) 2.udp协议 (1)如果如果收消息缓冲区里的数据为“空”,recvfrom也会阻塞 (2)只不过udp协议的客户端sendinto一个空数据并不是真的空数据(包含:空数据+地址信息,得到的报仍然不会为空),所以客户端只要有一个sendinto(不管是否发送空数据,都不是真的空数据),服务端就可以recvfrom到数据。 (3)udp无链接 无链接,因而无需listen(backlog),更加没有什么连接池之说了
无链接,udp的sendinto不用管是否有一个正在运行的服务端,可以己端一个劲的发消息,只不过数据丢失
recvfrom收的数据小于sendinto发送的数据时,在mac和linux系统上数据直接丢失,在windows系统上发送的比接收的大直接报错
只有sendinto发送数据没有recvfrom收数据,数据丢失 ==============注意:=============== 1.你单独运行上面的udp的客户端,你发现并不会报错,相反tcp却会报错,因为udp协议只负责把包发出去,对方收不收,我根本不管,而tcp是基于链接的,必须有一个服务端先运行着,客户端去跟服务端建立链接然后依托于链接才能传递消息,任何一方试图把链接摧毁都会导致对方程序的崩溃。 2.上面的udp程序,你注释任何一条客户端的sendinto,服务端都会卡住,为什么?因为服务端有几个recvfrom就要对应几个sendinto,哪怕是sendinto(b'')那也要有。 '''

什么是粘包(解法:定长报头)

须知:只有TCP有粘包现象,UDP永远不会粘包,为何,且听我娓娓道来

首先需要掌握一个socket收发消息的原理

所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。

Python(socket编程——2)的更多相关文章

  1. Python Socket 编程——聊天室示例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的 ...

  2. python/socket编程之粘包

    python/socket编程之粘包 粘包 只有TCP有粘包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提 ...

  3. PYTHON SOCKET编程简介

    原文地址: PYTHON SOCKET编程详细介绍   Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 Soc ...

  4. python socket编程笔记

    用python实现一个简单的socket网络聊天通讯 (Linux --py2.7平台与windows--py3.6平台) 人生苦短之我用Python篇(socket编程) python之路 sock ...

  5. [Python_7] Python Socket 编程

    0. 说明 Python Socket 编程 1. TCP 协议 [TCP Server] 通过 netstat -ano 查看端口是否开启 # -*-coding:utf-8-*- "&q ...

  6. Python Socket 编程示例 Echo Server

    简评:我们已经从「Python Socket 编程概览」了解了 socket API 的概述以及客户端和服务器的通信方式,接下来让我们创建第一个客户端和服务器,我们将从一个简单的实现开始,服务器将简单 ...

  7. Python Socket 编程——聊天室演示样例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和client的代码了解主要的 Python Socket 编程模型.本文再通过一个样例来加强一下对 Socket ...

  8. python socket编程入门(编写server实例)+send 与sendall的区别与使用方法

    python 编写server的步骤: 1. 第一步是创建socket对象.调用socket构造函数.如: socket = socket.socket( family, type ) family参 ...

  9. 第九章:Python高级编程-Python socket编程

    第九章:Python高级编程-Python socket编程 Python3高级核心技术97讲 笔记 9.1 弄懂HTTP.Socket.TCP这几个概念 Socket为我们封装好了协议 9.2 cl ...

  10. python socket编程详细介绍

    Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 SocketServer, 它提供了服务器中心类,可以简化网络 ...

随机推荐

  1. Linux中安装配置spark集群

    一. Spark简介 Spark是一个通用的并行计算框架,由UCBerkeley的AMP实验室开发.Spark基于map reduce 算法模式实现的分布式计算,拥有Hadoop MapReduce所 ...

  2. GitHub搭建个人网站续

    来源:http://www.cnblogs.com/crazyacking/p/4678976.html http://www.cnblogs.com/crazyacking/category/716 ...

  3. jenkins发布docker到mesos

    1.前提是装好git.SSH.maven插件 2.jenkins新建一个项目,配好git拉取代码.maven编译构建(gradle构建也行,这不重要) 3.SSH Server,填写需要传输的jar文 ...

  4. django头像上传详解

    使用form组件上传头像 实现的效果如下: 将默认的上传文件框隐藏起来变成了一个默认的头像 而且可以点击上传 处理步骤 avatar = forms.FileField( widget = widge ...

  5. 论坛模块__发帖时使用FCKeditor

    论坛模块__发帖时使用FCKeditor 测试 <html> <head> <meta http-equiv="content-type" conte ...

  6. Struts2_day03--课程安排_OGNL概述入门_什么是值栈_获取值栈对象_值栈内部结构

    Struts2_day03 上节内容 今天内容 OGNL概述 OGNL入门案例 什么是值栈 获取值栈对象 值栈内部结构 向值栈放数据 向值栈放对象 向值栈放list集合 从值栈获取数据 获取字符串 获 ...

  7. logback中MDC使用

    今天在项目发现别人写了很多MDC.put("taskid", "testThread/heart/main_heart");或者MDC.put("ta ...

  8. Zabbix-3.0.3结合Grafana-3.1.0给你想要的绘图

    导读 Grafana 是 Graphite 和 InfluxDB 仪表盘和图形编辑器.Grafana 是开源的,功能齐全的度量仪表盘和图形编辑器,支持 Graphite,InfluxDB 和 Open ...

  9. 搭建jsp运行环境

    一:搭建jsp服务器端运行环境的步骤: a,下载并按照JDK(JavaDevelopmentKit),这其中就包含了编译器,虚拟机,类库:. b,配置操作系统的环境变量PATH; 补充:编辑变量  添 ...

  10. sql 提升查询效率 group by option hash group

    问题: 一个程序查询经常超过20siis限制时间,排查问题后发现其中的一个存储过程时间会在15s左右 解决思路: 1:确认问题点 通过输出时间的方式查看存储过程中每个部分的执行时间,找到最耗时的三个过 ...