# ### tcp 循环发消息

import socket
# 1.创建一个对象
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 2.绑定ip,端口号,在网络上注册该主机
sk.bind( ("127.0.0.1",9004) )
# 3.监听端口
sk.listen() while True: # 4.建立三次握手
conn,addr = sk.accept()
# 5.收发数据的逻辑
# 该循环的作用:是循环发消息
while True:
# 接受消息
res = conn.recv(1024)
print(res.decode()) # 发送数据
strvar = input("请输入你要给对方的消息:")
conn.send(strvar.encode()) # 退出
if strvar == "q":
break # 6.四次挥手
conn.close()
# 7.退还端口
sk.close()
# ### tcp 客户端
import socket # 1.创建一个socket对象
sk = socket.socket() # 2.与服务器建立连接
sk.connect( ("127.0.0.1",9004) ) # 3.收发数据的逻辑 while True:
# 发送消息
strvar = input("请输入您要发送的消息:")
sk.send(strvar.encode())
# 接受消息
res = sk.recv(1024) if res == b"q":
break print(res.decode()) # 4.关闭连接
sk.close()

从上面的服务端与客户端我们可以知道,客户端无法单独存在,必须等待对应的服务端开启后才能与服务端开启通讯,而在TCP下的c/s模式下只能支持一客户端一服务器通话,而其他客户端连接进来无法做到实时通讯,必须等待前面的客户端断开连接后我才能与服务端交流,但同时也因为这个特性也早就了TCP下的传输数据稳定,不丢包等优点,缺点:速度慢连接拖拉

下面我们看看UDP下的socket是怎么样子的吧

服务端

# ### udp 服务端
import socket
# 1.创建一个socket对象
sk = socket.socket(type=socket.SOCK_DGRAM) # 2.绑定ip,端口号
sk.bind( ("127.0.0.1",9000) ) # 3.收发数据
# udp协议,如果作为服务器,第一次需要先接受消息,才能得到对方的ip和端口号
msg,cli_addr = sk.recvfrom(1024)
print(msg,cli_addr)
"""
b's9\xe6\x80\xbb\xe5\x86\xb3\xe8\xb5\x9b,lpl\xe5\x86\x8d\xe9\x80\xa0\xe8\xbe\x89\xe7\x85\x8c,\xe5\x87\xa4\xe5\x87\xb0\xe6\xb6\x85\xe6\xa7\x83' ('127.0.0.1', 53492)
"""
print(msg.decode()) # 发送数据给客户端
msg = "iG牛逼"
sk.sendto(msg.encode("utf-8"),cli_addr) # 4.关闭连接
sk.close()

客户端

# ### 客户端
import socket
# 1.创建socket对象
sk = socket.socket(type=socket.SOCK_DGRAM) # 2.收发数据
msg = "s9总决赛,lpl再造辉煌,凤凰涅槃"
# sendto(发送的二进制字节流消息,对方的ip和端口[元组])
sk.sendto(msg.encode("utf-8"),("127.0.0.1",9000)) # 接受数据
msg,addr = sk.recvfrom(1024)
print(msg.decode("utf-8"))
print(addr) # 3.关闭udp连接
sk.close

从上面我们可以看出,UDP协议下连接服务器时不会因为TCP的三次握手跟四次挥手而造成的连接拖沓,因为这个特点理论上可以同时又多个客户端同时连接服务器,而服务器可以同时给这些客户端提供服务,且不会理客户端的当前的连接状态,我只管发,但你收不收我不管,udp协议是基于这样的情况下运作的,那么UDP跟TCP的对比有啥优点呢?

快,不仅连接快,传输速度也快,但同时也造就了容易丢包,解决方法  创建缓存区,把数据一股气全部丢到缓存区里让客户端子去取,这样避免造成大面积丢包

这两种协议在传输数据时都存在黏包现象,为什么呢?

因为数据传输过程中服务端发送的太快,而客户端接收的太慢了,也就造成了数据黏包,从而造成数据紊乱,

解决这个问题有两个方案

(1)在服务端与客户端加延时可以避免黏包的现象发生

(2)把要传送的数据大小先发送给客户端,然后约定好每次发送多少,通过这样准确的发送与接收也可以避免黏包现象的发生

下面我通过代码来解释这个现象

# ### 黏包 服务端

import socket
import time
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 在网络上注册该主机
sk.bind( ("127.0.0.1",9001) )
# 监听端口
sk.listen()
# 三次握手
conn,addr = sk.accept()
# 处理收发数据的逻辑 # 在真正第一次发送数据之前,把真实的数据长度先发过去
conn.send("".encode()) # 第一次发送
msg = "hello," * 20
conn.send(msg.encode())
# time.sleep(0.1)
# 第二次发送
conn.send("world".encode()) # 四次挥手
conn.close()
# 退还端口
sk.close()
# ### 客户端

import socket
import time
# 创建一个tcp对象
sk = socket.socket()
# 连接服务器
sk.connect( ("127.0.0.1",9001) ) time.sleep(0.2) # 接受发送过来的真实的数据长度
res = sk.recv(8)
num = int(res.decode("utf-8"))
# 处理收发数据逻辑
res1 = sk.recv(num) # hello,
res2 = sk.recv(1024) # world
print(res1)
print(res2)
# 关闭链接
sk.close()

这是通过延时接收隔离了黏包现象,简单点就是接收速度变慢了

不推荐这种用法,影响效率

下面第二种

# ### 客户端

import socket
import time
# 创建一个tcp对象
sk = socket.socket()
# 连接服务器
sk.connect( ("127.0.0.1",9001) ) time.sleep(0.2) # 接受发送过来的真实的数据长度
res = sk.recv(8)
num = int(res.decode("utf-8"))
# 处理收发数据逻辑
res1 = sk.recv(num) # hello,
res2 = sk.recv(1024) # world
print(res1)
print(res2)
# 关闭链接
sk.close()
# ### 客户端
import socket
import struct sk = socket.socket()
sk.connect( ("127.0.0.1",9000) ) # 处理收发数据的逻辑
# 接受第一次发送过来的长度
n = sk.recv(4)
tup = struct.unpack("i",n)
n = tup[0]
print(n,type(n)) # 接受第二次发送过来的真实数据
res1 = sk.recv(n)
print(res1.decode("utf-8")) res2 = sk.recv(1024)
print(res2.decode("utf-8"))
# 关闭链接
sk.close()

这种就是我上面说的那样,通过先计算文件大小然后在跟客户端商量好每次发多少给你客户端接收多少,即避免了黏包,又提升力了效率

python-网络编程socket模块详解的更多相关文章

  1. java网络编程Socket通信详解

    Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Socket.像大家熟悉的QQ.MSN都使用了Socket相关的技术. ...

  2. python 网络编程--socket模块/struct模块

    socket模块: 客户端:CS架构,  client -> server 浏览器:BS架构,  browser -> server 网络通信本质:传输字节 doc命令查看ip地址:ipc ...

  3. (转)python标准库中socket模块详解

    python标准库中socket模块详解 socket模块简介 原文:http://www.lybbn.cn/data/datas.php?yw=71 网络上的两个程序通过一个双向的通信连接实现数据的 ...

  4. Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制

    Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...

  5. Java网络编程和NIO详解开篇:Java网络编程基础

    Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为 ...

  6. Java网络编程和NIO详解8:浅析mmap和Direct Buffer

    Java网络编程与NIO详解8:浅析mmap和Direct Buffer 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NI ...

  7. Java网络编程和NIO详解9:基于NIO的网络编程框架Netty

    Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...

  8. 铁乐学Python_Day33_网络编程Socket模块1

    铁乐学Python_Day33_网络编程Socket模块1 部份内容摘自授课老师的博客http://www.cnblogs.com/Eva-J/ 理解socket Socket是应用层与TCP/IP协 ...

  9. Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理

    Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博 ...

随机推荐

  1. Redis学习(二)Redis的安装

    Window 下安装 下载地址:https://github.com/MSOpenTech/redis/releases. Redis 支持 32 位和 64 位.这个需要根据你系统平台的实际情况选择 ...

  2. CompareAndSwap原子操作原理

    在翻阅AQS(AbstractQueuedSynchronizer)类的过程中,发现其进行原子操作的时候采用的是CAS.涉及的代码如下: 1: private static final Unsafe ...

  3. C语言笔记 02_基本语法&数据类型&变量

    基本语法 令牌 C 程序由各种令牌组成,令牌可以是关键字.标识符.常量.字符串值,或者是一个符号.例如,下面的 C 语句包括五个令牌: printf("Hello, World! \n&qu ...

  4. 熔断器Hystrix及服务监控Dashboard

    服务雪崩效应 当一个请求依赖多个服务的时候: 正常情况下的访问 : 但是,当请求的服务中出现无法访问.异常.超时等问题时(图中的I),那么用户的请求将会被阻塞. 如果多个用户的请求中,都存在无法访问的 ...

  5. java 网站源码 在线编辑模版 代码编辑器 兼容手机平板PC freemaker 静态引擎

    前台: 支持四套模版, 可以在后台切换   系统介绍: 1.网站后台采用主流的 SSM 框架 jsp JSTL,网站后台采用freemaker静态化模版引擎生成html 2.因为是生成的html,所以 ...

  6. Eclipse如何重置窗口

    https://jingyan.baidu.com/article/915fc41459585f51394b20c3.html 在Eclipse进行开发的时候,我们经常会由于这个窗口或者那个窗口没有打 ...

  7. 3、nio中的selector使用

    通过编写一个客户端和服务器端的例子来熟悉selector的使用 服务端逻辑: 1. 绑定一个端口号2. channel注册到selector中3. 用死循环来监听如果有时间发生,遍历selection ...

  8. navicat连接不上Linux服务器上的mysql的解决办法

    一开始,心情是沉痛的,截图如下: 转载请注明出处:https://www.cnblogs.com/NaughtyCat/p/how-to-connect-to-mysql-on-linux-by-na ...

  9. Docker动态添加端口,不需要重新建立镜像

    Docker容器在运行期间有时可能会需要修改或者添加暴露的端口,但是有时候运行的容器又不想再另外建立一个新的镜像.这时可以找到docker容器的存放地方,然后直接修改配置文件. 我们的容器都是保存在/ ...

  10. 使用gitolite搭建Git服务器

    使用gitolite搭建Git服务器 运行环境 Ubuntu18.04 gitolite 搭建过程 安装好Ubuntu18.04系统 更新系统 sudo apt update sudo apt upg ...