鄙人学习笔记


文章目录

  • 套接字介绍
      • 定义
      • 套接字分类(针对TCP和UDP的分类)
    • TCP套接字编程
      • 服务端流程
      • 代码实现
        • 举个例子
      • 客户端流程
      • 代码实现
        • 举个例子
      • TCP套接字数据传输特点
        • 做个练习
      • 网络收发缓冲区
        • 举个例子
      • TCP粘包

套接字介绍

定义

套接字是实现网络编程进行数据传输的一种技术手段

套接字分类(针对TCP和UDP的分类)

①流式套接字(SOCK_STREAM): 以字节流方式(就像是管道中的水流一样)传输数据,实现TCP网络传输方案。

②数据报套接字(SOCK_DGRAM):以数据报形式(就像是用瓶子打包好的水一样)传输数据,实现UDP网络传输方案。

TCP套接字编程

服务端流程

先来看一个流程图:

代码实现

  1. 创建套接字
sockfd=socket.socket(socket_family=AF_INET,socket_type=SOCK_STREAM,proto=0)
功能:创建套接字对象
参数:
socket_family  网络地址类型:AF_INET表示ipv4
socket_type  套接字类型:SOCK_STREAM 流式;SOCK_DGRAM 数据报
proto(在应用层网络编程中用不到) 选择子协议:通常为0
返回值: 套接字对象

备注:底层/系统层套接字也针对某种协议,这些协议,有的时候会产生一些分支,也就是子协议。那么为啥在应用层网络编程中用不到proto这个参数呢?因为TCP协议和UDP协议没有子协议,所以参数设为0,即不选择任何子协议。

  1. 绑定地址
sockfd.bind(addr)
功能: 绑定本机网络地址(如果不写本机网络地址,则会报错)
参数: 二元元组 (ip,port)  比如('0.0.0.0',8888)

备注:addr为一个元组,这个元组有两个元素一个是网络地址(IP),一个是端口号(port)。

  1. 设置监听
sockfd.listen(n)
功能 : 将套接字设置为监听套接字,确定监听队列大小
参数 : 监听队列大小

备注1:并不是所有的套接字都具备监听的功能,即被客户端连接的功能。通过调用listen,我们的套接字对象才能被客户端连接。

备注2:一个服务端套接字对象可以同时连接多个客户端,与客户端进行连接需要进行3次握手,且连接的过程需要一个一个来进行。比如说,同时有5个客户端发起了连接请求,这时我们就会形成一个”先来后到”的队列,对这5个客户端的连接请求,一个一个进行处理。比如说,我们设置监听队列大小为5,表示队列最多容纳5个客户端等待处理。但有10个客户端同时发起了连接请求,这时,服务端会先处理第1个发起请求的那个客户端,前2~6个客户端则在等待队列中,最晚发起请求的4个客户端,则会被拒绝。

  1. 等待处理客户端连接请求
connfd,addr = sockfd.accept()
功能: 阻塞等待处理客户端请求(等待客户端连接,啥时候有客户端连接,才结束阻塞)
返回值:connfd : 客户端连接套接字.客户端连接后,新产生的专门与客户端进行通信的套接字对象。则每当有一个客户端连接时,都会有一个新的专用于连接的套接字对象产生。就像对每个客户端提供一个专属管家一样,提升用户端体验。我们如果找到一个连接套接字,就可以知道它对应的客户端是谁addr :连接的客户端地址

阻塞函数:当程序运行到这个函数时,则程序暂停执行。程序在等待某种条件,当条件满足后才继续执行,如:input()、sleep()。阻塞函数在IO操作中很常见。

  1. 消息收发
data = connfd.recv(buffersize)
功能 : 接受客户端消息
参数 :每次最多接收消息的大小(最多一次接受多少字节的消息)
返回值: 接收到的内容
n = connfd.send(data)
功能 : 发送消息
参数 :要发送的内容-bytes格式(字节串格式)
返回值: 发送的字节数

备注1:所有和网络相关的消息传送都得是bytes格式(字节串格式).发送和接收都得是字节串。

备注2:我们发送/接收的是字节串,但平时写/读的是字符串,所以我们需要用encode()/dencode()进行转换。

  1. 关闭套接字
sockfd.close()
功能:关闭套接字
举个例子

服务端代码:

import socket#创建流式套接字
sockfd = socket.socket(socket.AF_INET, \socket.SOCK_STREAM)
#绑定地址
sockfd.bind(('127.0.0.1', 8888))#设置监听
sockfd.listen(5)#等待处理客户端链接
print("Waiting for connect....")
connfd, addr = sockfd.accept()#收发消息
data = connfd.recv(1024)
print("接收到的消息:", data.decode())n = connfd.send(b'Receive your message')
print("发送了 %d 个字节数据" % n)#关闭套接字
connfd.close()
sockfd.close()

我们运行一下,得到以下结果:

结果说明,程序阻塞在accept,等待客户端连接。所以这时,我们就要找一个客户端与之连接,下一节,我们就学一下客户端流程。

客户端流程

先看看流程图:

代码实现

  1. 创建套接字(和客户端代码相同)
    注意:只有相同类型的套接字才能进行通信

  2. 请求连接

sockfd.connect(server_addr)
功能:连接服务器
参数:元组  服务器地址
  1. 收发消息(和客户端代码相同)
    注意: 为了防止两端都阻塞,故recv和send要配合使用。比如,服务端是先send后recv,那么客户端则需要先recv后send。否则,若两端同时recv,则两端都会阻塞。

  2. 关闭套接字(和客户端代码相同)

举个例子

客户端代码:

服务端代码:

我们想要运行,但是若先运行客户端,则会报错。所以我们要先启动服务端

①运行服务端

查看服务端的控制台Console 2/A输出的结果:

②运行客户端

我们先看一下服务端的控制台Console 2/A输出的结果:

我们再看一下客户端的控制台Console 3/A输出的结果:

消息收发成功了,很好~

TCP套接字数据传输特点

①TCP连接中,当一端退出,另一端如果阻塞在recv,此时recv会立即返回一个空字串。
②TCP连接中,如果一端已经不存在,仍然试图通过send发送信息,则会产生BrokenPipeError
③一个监听套接字可以同时连接多个客户端,也能够重复被连接。

做个练习

要求1:一个客户端退出了,服务器不会退出,而是连接下一个客户端
要求2:客户端可以不停的循环发送消息

服务端代码:

#-*- coding: utf-8 -*-import socket#创建流式套接字
sockfd = socket.socket(socket.AF_INET, \socket.SOCK_STREAM)#绑定地址
sockfd.bind(('127.0.0.1', 8888))#设置监听
sockfd.listen(5)#等待处理客户端链接
while True:print("Waiting for connect....")try:connfd, addr = sockfd.accept()print("Connect from:", addr)except KeyboardInterrupt:print("退出服务")break# 收发消息while True:data = connfd.recv(1024)# 得到空则退出循环if not data:breakprint("接收到的消息:", data.decode())n = connfd.send(b'Receive your message')print("发送了 %d 个字节数据" % n)connfd.close()#关闭套接字
sockfd.close()

客户端代码:

#-*- coding: utf-8 -*-from socket import *#创建tcp套接字
sockfd = socket()#发起连接
server_addr = ('127.0.0.1',8888)
sockfd.connect(server_addr)#收发消息
while True:data = input("消息:")if not data:breaksockfd.send(data.encode())data = sockfd.recv(1024)print("From server:",data.decode())#关闭
sockfd.close()

先运行服务端,再运行客户端并发送消息。

客户端结果:

服务端结果:

网络收发缓冲区

①网络缓冲区有效的协调了消息的收发速度、缓解收发压力。
②send和recv实际是向缓冲区发送接收消息,当缓冲区不为空recv就不会阻塞。

网络缓冲区完成消息传递示意图:

举个例子

还记得我们上面那个练习么?其中一段代码是:


它表示,每次最多可接收消息大小为1024个字节.

我们来更改一下最大可接受的消息字节数为5:

用客户端发送消息:

服务端结果:

客户端结果:

则说明,客户端1次发送,服务端分3次接收了,同时返回给服务端3句’ Receive your message’也就是说,服务端的内层循环(如下图所示)循环了3次

备注1:所以我们一开始说【函数recv()是阻塞函数,当发送方不发消息,就会阻塞】。但其实更准确的来说,并不是发送方不发消息就会阻塞,接收方其实是先从缓冲区去拿消息,当缓冲区为空时,会阻塞,当缓冲区一直有消息时,则会一直获取消息,一直不阻塞。

注意! 运行上面的代码时,客户端有时候也会出现以下这种情况:

按照上面的说法,当客户端发送1条消息,客户端会返回3条’ Receive your message’。但是也会出现,当第1条’ Receive your message’进入客户端缓冲区,客户端就从客户端缓冲区recv()了这条消息,导致剩下2条’ Receive your message’停留在缓冲区没被接受。等到下一次,客户端再从缓冲区中recv()时,才把剩下’ Receive your message’接收到。

备注1:我们第一次运行代码时,服务端快速的连续3次send()了1条’ Receive your message’,客户端1次recv()了3条’ Receive your message’。接收端一次接收了多条发送端消息,我们称这种情况叫:粘包

TCP粘包

  • 原因
    TCP以字节流方式传输,没有消息边界。多次发送的消息被一次接收,此时就会形成粘包。

  • 影响(分情况,比如:传一部电影/发送用户名消息)
    ①如果发送的内容中,每个信息都有独立的含义(比如:发送几个用户姓名),需要接收端独立解析,此时,这时粘包会有影响。
    ②如果发送的是一个字节流文件,是一个连在一起的整体(比如:发送一部电影),接收端无需单独解析,而是将所有接收到内容最终合成一个整体,这时粘包没啥影响。

  • 处理方法
    ①人为的添加消息边界,比如:每次发送一个姓名时,在姓名后加一个特殊符号。
    ②控制发送速度(因为粘包的产生是因为收发速度不协调),比如用sleep()函数调节。

网络编程(part9)--socket套接字编程之TCP套接字相关推荐

  1. 网络编程(part10)--socket套接字编程之UDP套接字

    鄙人学习笔记 文章目录 UDP套接字编程 服务端流程 举个例子 客户端流程 举个例子 TCP套接字和UDP套接字编程区别 UDP套接字编程 服务端流程 创建数据报套接字 sockfd = socket ...

  2. 【JavaEE】网络编程之TCP套接字、UDP套接字

    目录 1.网络编程的基本概念 1.1为什么需要网络编程 1.2服务端与用户端 1.3网络编程五元组 1.4套接字的概念 2.UDP套接字编程 2.1UDP套接字的特点 2.2UDP套接字API 2.2 ...

  3. python界面编程和网口通信_Python—网络通信编程之tcp通信编程

    服务端代码 import socket # 1.创建流式套接字实例 # server = socket.socket() server = socket.socket(socket.AF_INET, ...

  4. 网络套接字编程之IO模型详解

    网络套接字编程之IO模型详解 本文主要参考自<UNIX网络编程>(第1卷)(套接口API第3版) Unix下可用的五种I/O模型有: 阻塞式I/O 非阻塞式I/O I/O复用(select ...

  5. Python 网络编程(Socket)

    Python 网络编程(Socket) 一.Socket 套接字 1.Socket 编程 socket本质是编程接口(API),对TCP/IP的封装,提供可供程序员做网络开发所用的接口.Socket ...

  6. C++笔记--Linux网络编程(15-0)-socket(供自查,文档说明)

    目录 网络基础 协议的概念 什么是协议 典型协议 网络应用程序设计模式 C/S模式 B/S模式 优缺点 分层模型 OSI七层模型 TCP/IP四层模型 通信过程 协议格式 数据包封装 以太网帧格式 A ...

  7. 网络编程(1)--socket/bind/listen/accept的简单介绍

    网络编程1--socket/bind/listen/accept的简单介绍 背景介绍 网络编程接口 socket bind listen accept 背景介绍 最近在学习APUE和Linux高性能服 ...

  8. Java网络编程:socket与Netty

    Java网络编程:socket与Netty Java网络编程:socket与Netty TCP/IP介绍 简介 数据传输 TCP粘包和黏包 现象 为什么出现 如何解决 Socket介绍 介绍 功能开发 ...

  9. java 网络编程简单聊天_网络编程之 TCP 实现简单聊天

    网络编程之 TCP 实现简单聊天 客户端 1.连接服务器 Socket 2.发送消息 package lesson02;import java.io.IOException;import java.i ...

最新文章

  1. 新疆银行招聘计算机,新疆2017年银行招聘考试计算机学_计算机基础试题(19页)-原创力文档...
  2. 【实验】通过IGMP实现接收组播视频信息案例
  3. css 中的伪类选择器before 与after
  4. 可观测性PHP秩判据,线性系统的可控性与可观测性
  5. 作者:胡晓惠(1960-),男,中国科学院软件研究所研究员,天基综合信息技术实验室常务副主任...
  6. 64位windows系统如何显示32位dcom组件配置
  7. RabbitMQ 基本使用(注解的方式)
  8. java中的与或运算
  9. 单元测试新方法:用setUp方法 @Before注释
  10. 求解函数优化问题的改进布谷鸟搜索算法
  11. [MQ]什么是消息队列?
  12. 心如赤子,不贪不骄不纵
  13. 北大计算机博士毕业难度,北京大学博士毕业要求
  14. 联想E43升级bios激活windows 7
  15. C++笔试笔记1(4399 西山居 深信服 剑心互娱 快手)
  16. 怎么修改PDF文件的文字内容
  17. windows.frames
  18. ITRON的内存管理,中断处理,时钟管理
  19. python小游戏 仿谷歌浏览器小恐龙小游戏设计与实现
  20. Windows AD证书服务系列---部署CA(1)

热门文章

  1. 深度学习(四十三)——深度强化学习(6)AlphaGo全系列
  2. 机器学习(一)——线性回归、分类与逻辑回归
  3. vue 悬浮按钮_Vue@哇!几行代码实现拖拽视图组件
  4. Oracle 计算两个日期间隔的天数、月数和年数
  5. cocos2dx build_native.sh clean 命令报错的解决
  6. 观察+|腾讯网易终获游戏版号,但all in 游戏时代已结束
  7. 网络分流器|运营商光纤延距解决方案
  8. Laravel核心代码学习--用户认证系统(基础介绍)
  9. python使用ffmpeg截取视频段
  10. (1)kendo UI使用基础介绍与问题整理——简单说明