网络编程(TCP/IP协议/套接字等)

 

文章目录

01、网络通信概述

02、TCP/IP协议

03、socket编程

04、socket中的TCP与UDP

05、并发服务器

01、网络通信概述

 1、什么是网络?

简单意义上来说,网络就是⼀种辅助双⽅或者多⽅能够连接在⼀起的⼯具。

官方对于网络的定义为:

网络是由若干节点和连接这些节点的链路构成,表示诸多对象及其相互联系。

在1999年之前,人们一般认为网络的结构都是随机的。但随着Barabasi和Watts在1999年分别发现了网络的无标度和小世界特性并分别在世界著名的《科学》和《自然》杂志上发表了他们的发现之后,人们才认识到网络的复杂性。 [1] 

网络会借助文字阅读、图片查看、影音播放、下载传输、游戏、聊天等软件工具从文字、图片、声音、视频等方面给人们带来极其丰富的生活和美好的享受。

2、我们使用网络的目的

联通多⽅然后进⾏通信⽤的,即把数据从⼀⽅传递给另外⼀⽅。

⽤⽹络能够把多⽅链接在⼀起,然后可以进⾏数据传递

⽹络编程就是,让在不同的电脑上的软件能够进⾏数据传递,即进程之间的通信,如下图:

                      网络编程(TCP/IP协议/套接字等)_第1张图片

02、TCP/IP协议

1、什么是网络通信协议

  • 网络通信协议是一种网络通用语言,为连接不同操作系统和不同硬件体系结构的互联网络提供通信支持,是一种网络通用语言。
  • 比如我们日常生活中,有的人说英语,有的人说中⽂,有的人说德语,说同⼀种语⾔的⼈可以交流,不同的语⾔之间就不⾏了 为了解决不同种族⼈之间的语⾔沟通障碍,现规定国际通⽤语⾔是英语,这就是⼀个规定,这就是协议。
  • 再比如,网络中一个微机用户和一个大型主机的操作员进行通信,由于这两个数据终端所用字符集不同,因此操作员所输入的命令彼此不认识。为了能进行通信,规定每个终端都要将各自字符集中的字符先变换为标准字符集的字符后,才进入网络传送,到达目的终端之后,再变换为该终端字符集的字符。因此,网络通信协议也可以理解为网络上各台计算机之间进行交流的一种语言。
  • 常见的网络通信协议有:TCP/IP协议(最常用)、IPX/SPX协议、NetBEUI协议等。

2、什么是TCP/IP协议

  • TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议) 协议具有很强的灵活性,支持任意规模的网络,几乎可连接所有服务器和工作站。在使用TCP/IP协议时需要进行复杂的设置,每个结点至少需要一个“IP地址”、一个“子网掩码”、一个“默认网关”、一个“主机名”,对于一些初学者来说使用不太方便。
  • 就像说不同语⾔的⼈沟通⼀样,只要有⼀种⼤家都认可都遵守的协议即可, 那么这个计算机都遵守的⽹络通信协议叫做 TCP/IP协议。
  • 互联⽹协议包含了上百种协议标准,但是最重要的两个协议是TCP和IP 协议,所以,⼤家把互联⽹的协议简称TCP/IP协议

3、TCP/IP分层协议

TCP/IP参考模型是首先由ARPANET所使用的网络体系结构,共分为四层(个别参考把其分为5层):网络接口层(又称链路层)、网络层(又称互联层)、传输层和应用层,每一层都呼叫它的下一层所提供的网络来完成自己的需求。

每一层对应的协议有:

  • 网络接口层协议:Ethernet 802.3、Token Ring 802.5、X.25、Frame relay、HDLC、PPP ATM等。
  • 网络层协议:IP(Internet Protocol,英特网协议)、ICMP(Internet Control Message Protocol,控制报文协议)、ARP(Address Resolution Protocol,地址转换协议)、RARP(Reverse ARP,反向地址转换协议)。
  • 传输层协议: TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram protocol,用户数据报协议)。
  • 应用层协议:FTP(File Transfer Protocol,文件传输协议)、TELNET(用户远程登录服务协议)、DNS(Domain Name Service,是域名解析服务)、SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)、NFS(Network File System,网络文件系统)、HTTP(Hypertext Transfer Protocol,超文本传输协议)。

                            网络编程(TCP/IP协议/套接字等)_第2张图片

1)IP地址

1、定义:IP地址是一种在Internet上的给主机编址的方式,也称为网际协议地址。

2、作用:⽤来在⽹络中标记⼀台电脑的⼀串数字,⽐如192.168.1.1;在本地局域⽹上是惟⼀的。

                        网络编程(TCP/IP协议/套接字等)_第3张图片

3、分类:每⼀个IP地址包括两部分:⽹络地址和主机地址 ,有如下几种类型:

 网络编程(TCP/IP协议/套接字等)_第4张图片
4、私有IP:⽹络IP中,国际规定有⼀部分IP地址是⽤于局域⽹使⽤,也 就是属于私⽹IP,不在公⽹中使⽤的,它们的范围是:                                                

                        10.0.0.0~10.255.255.255    

                         172.16.0.0~172.31.255.255     

                          192.168.0.0~192.168.255.255

5、回环地址IP: 

  •  IP地址127.0.0.1 代表本机IP地址,等价于localhost, ⽤ http://127.0.0.1 就可以测试本机中配置的Web服务器。
  • 127.0.0.1,通常被称为本地回环地址(Loop back address),不属于任何一个有类别地址类。它代表设备的本地虚拟接口,所以默认被看作是永远不会宕掉的接口。在windows操作系统中也有相似的定义,所以通常在不安装网卡前就可以ping通这个本地回环地址。一般都会用来检查本地网络协议、基本数据接口等是否正常的。

6、子网掩码:⼦⽹掩码不能单独存在,它必须结合IP地址⼀起使⽤。

⼦⽹掩码的作⽤: 将某个IP地址划分成⽹络地址和主机地址两部分. ⼦⽹掩码的设定        

必须遵循⼀定的规则, 用来判断两个IP是否在同一个网络。

                         A: 172.25.254.18/24

                         B: 172.25.0.10/24

7、端口:端⼝就好⼀个房⼦的⻔,是出⼊这间房⼦的必经之路。

    端⼝号只有整数,范围是从0到65535;

    下面列举一些常用的服务及端口号:

HTTP

80
FTP 21
SSH 22
Telnet 23
SMTP 25

HTTP

443
POP2 109
POP3 110
DHCP Client 546
DHCP Server 547
MSN 569
SSL 990
IMAP 993
Worm.Sasser.e 1023
sqlserver 1433
Oracle 1521
MySql 3306

8、linux中如何查看端口呢?

在命令行输入:cat /etc/services | less 即可查看所需要的查看的服务的端口。

(当然,前提是你的主机安装了你所要查询的服务才能够查询到) 

比如:查看http服务的端口:命令行输入:cat /etc/services | less (可以查看规定好的服务对应的端口号)

然后输入/http就可以查询到端口;

网络编程(TCP/IP协议/套接字等)_第5张图片

可见查询到的http服务的端口为80.


03、socket编程

1、为什么需要socket?

通过之前的学习, 我们知道本地间通信(IPC)有队列、同步(互斥锁、条件变量等)、以及管道等方法。

但是不同主机之间如果需要通信,则就需要用到socakt.

问题: 本地通过进程PID来唯⼀标识⼀个进程,在⽹络中如何唯⼀标识⼀个进程?

⽹络层的“IP地址”可以唯⼀标识⽹络中的主机,⽽传输层的“协议+端⼝”可以唯⼀标识主机中的应⽤程序(进程)。因此利用IP地址,协议,端⼝就可以标识⽹络的进程。

2、什么是socket?

 套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。

简单来说:socket(简称套接字) 是进程间通信的⼀种⽅式, 能实现不同主机间的进程间通信,我们⽹络上各种各样的服务⼤多都是基于 Socket 来完成通信的。比如以下服务等都是基于socket 来完成通信的。

网络编程(TCP/IP协议/套接字等)_第6张图片

3、创建socket

在 Python 中 使⽤socket 模块的函数 socket 就可以完成:     

socket.socket(AddressFamily, Type)   

 1). Address Family:         

AF_INET: IPV4⽤于 Internet 进程间通信         AF_INET6: IPV6⽤于 Internet 进程间通信     

2). Type:套接字类型         

SOCK_STREAM: 流式套接字,主要⽤于 TCP 协议         SOCK_DGRAM: 数据报套接字,主要⽤于 UDP 协 议

import socket

# 1. 创建socket对象
#       family: AF_INET(IPv4)   AF_INET6(IPv6)      ========= 网络层协议
#       type: # SOCK_STREAM(TCP)   SOCK_DGRAM(UDP) ========== 传输层协议
#       Linux: 可以认为是一个文件;
socketObj = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
print(socketObj.getsockname())

#2.  关闭socket对象
socketObj.close()

# 2. socket基本使用
import os
os.system('hostname')

hostname = socket.gethostname()
print("主机名:", hostname)

print(socket.gethostbyname('localhost'))

小练习如下:创建⼀个tcp socket(tcp套接字)  

           把代码中的Type:套接字类型写成 SOCK_STREAM

                  创建⼀个udp socket(udp套接字)

           把代码中的Type:套接字类型写成 SOCK_DGRAM 即可

04、socket中的UDP与TCP

1、UDP

1)什么是UDP

  • UDP ⽤户数据报文协议,是⼀个⽆连接的简单的⾯向数据报文运输层(传输层)协议。UDP不提供可靠性,它只是把应⽤程序传给IP层的数据报发送出去,但 是并不能保证它们能到达⽬的地。
  • 由于UDP在传输数据报前不⽤在客户和服 务器之间建⽴⼀个连接,且没有超时重发等机制,故⽽传输速度很快。
  • UDP是⼀种⾯向⽆连接的协议,每个数据报都是⼀个独⽴的信息,包括完整 的源地址或⽬的地址,它在⽹络上以任何可能的路径传往⽬的地,因此能否到达⽬的地,到达⽬的地的时间以及内容的正确性都是不能被保证的。

2)UDP的特点

  • UDP是⾯向⽆连接的通讯协议,UDP数据包括⽬的端⼝号和源端⼝号信息, 由于通讯不需要连接,所以可以实现⼴播发送。
  • UDP传输数据时有⼤⼩限 制,每个被传输的数据报必须限定在64KB之内。
  • UDP是⼀个不可靠的协议,发送⽅所发送的数据报并不⼀定以相同的次序到达接收⽅。

                     网络编程(TCP/IP协议/套接字等)_第7张图片

3)UDP应用场景

UDP是⾯向消息的协议,通信时不需要建⽴连接,数据的传输⾃然是不可靠 的,UDP⼀般⽤于多点通信和实时的数据业务,⽐如:     

  • 语⾳⼴播     
  • 视频     
  • QQ     
  • TFTP(简单⽂件传送)   
  •  SNMP(简单⽹络管理协议)   
  •  DNS(域名解释(域名服务器))等等

4)UDP⽹络程序

通过UDP通信服务的过程: 无论是服务端还是客户端,都需要首先建立一个socket()对象将来进行通信,服务端需要绑定一个IP或一个端口。客户端想要给客户端发消息,由于UDP是无连接的,所以客户端不需要通知服务端,直接发送就好了,消息发送之后,服务端优势会做出一个响应回复给客户端,然年后客户端会进行接收,这样一次通信就结束了。当客户端决定 不发消息了,此时就可以结束掉socket()对象了。(当然,如果服务端也不想让别人给发送消息的时候,也可以吧自己的socket()对象结束掉。)图解如下:

                         网络编程(TCP/IP协议/套接字等)_第8张图片

               网络编程(TCP/IP协议/套接字等)_第9张图片

实验: 

服务端(UDP Server):提供服务
创建socket对象 ---- 绑定IP和端口 ---- 接收信息 ---- 发送消息(一个响应) ---- 关闭

客户端(UDP Client):访问提供的服务
创建socket对象 ---- 发送消息 ---- 接收消息 ---- 关闭

同一个目录下创建两个.py文件
服务端.py ; 客户端.py

《1》在服务端:

import socket

# 1.实例化socket对象
udpServer = socket.socket(family=socket.AF_INET,type=socket.SOCK_DGRAM)
# 2.绑定IP和端口,注意是一个元组
udpServer.bind(('0.0.0.0', 9001))  #0.0.0.0代表开放所有的IP地址
print('等待客户端UDP的连接。。。')
# 3.接收客户端的消息
recvdata, address = udpServer.recvfrom(1024)  # 会有两个返回值:发送的消息;哪个地址发来的(IP地址,端口地址)。是一个元组。最多1024个字节
print('接收到客户端的数据为:',recvdata.decode('utf-8'))   # socket传输的数据是一个bytes类型 :b'hello' ,将它转为字符串
# 4.给客户端回复消息,发送的消息必须是bytes类型
udpServer.sendto(b'hello client',address)
# 5.关闭socket对象
udpServer.close()

《2》在客户端:

import socket

# 1.创建socket对象
udpClient = socket.socket(family=socket.AF_INET,type=socket.SOCK_DGRAM)
# 2.客户端发送消息,发送的消息必须是bytes类型
udpClient.sendto(b'hello server',('192.168.1.104',9001)) #发给哪台主机的哪个端口
# 3.接收服务端的消息
recvdata,address = udpClient.recvfrom(1024)
print('接收到服务端的数据为:',recvdata.decode('utf-8'))
# 4.关闭socket对象
udpClient.close()

分别运行结果为:

《1》服务端为:

《2》客户端为:

5)UDP协议案例:(模拟QQ聊天)

注:python2中可以之间传字符串
      python3中只能传输bytes类型的数据

     bytes类型与字符串类型的相互转换:
     bytes —> str:bytesobj.decode(‘utf-8’)
     str —> bytes:str.encode(‘utf-8’)

"""服务端"""
import socket

udpserver = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
udpserver.bind(('0.0.0.0', 9999))
print('QQ用户A上线.........')
while True:
    # 返回的是元组, 每一个元素是客户端发送的信息, 第二个元素是客户端和服务端交互的地址(IP, port)
    recv_data, address = udpserver.recvfrom(1024)
    # print(address)
    print("B:>> ", recv_data.decode('utf-8'))
    if recv_data == b'quit':
        print("聊天结束.......")
        break
    # 发送的消息必须是bytes类型
    #   bytes -->  str    bytesObj.decode('utf-8')
    #    str   --> bytes   strObj.encode('utf-8')
    send_data = input('A: >> ').encode('utf-8')
    if not send_data:
        continue
    udpserver.sendto(send_data, address)

udpserver.close()
"""客户端"""
import socket

udpclient = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)

print("QQ用户B上线.........")
while True:
    send_data = input('B:>> ').encode('utf-8')
    if not send_data:
        continue
    udpclient.sendto(send_data, ('172.25.254.197', 9999))
    if send_data == b'quit':
        print("聊天结束.....")
        break
    recv_data, address = udpclient.recvfrom(1024)
    print("A:>> ", recv_data.decode('utf-8'))

udpclient.close()

运行结果为:

《1》服务端(A)为:

网络编程(TCP/IP协议/套接字等)_第10张图片

《2》客户端(B)为:

网络编程(TCP/IP协议/套接字等)_第11张图片

2、TCP

1)什么是TCP

  • TCP: 传输控制协议(英语:Transmission Control Protocol,缩写为TCP)是一种面向连接的、可靠的基于字节流传输层通信协议。
  • TCP旨在适应支持多网络应用的分层协议层次结构。 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务。TCP假设它可以从较低级别的协议获得简单的,可能不可靠的数据报服务。
  • 原则上,TCP应该能够在从硬线连接到分组交换或电路交换网络的各种通信系统之上操作。
  • 是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议。

2)TCP网络程序

TCP协议通信的大致过程:首先,服务端和客户端都需要先建立socket()对象——服务端绑定IP和端口——服务端进行监听(为了保证有客户端和服务端进行连接)—— 监听结束如果有客户端和服务端连接,则可允许客户端建立连接(accept())——客户端发出连接信号——服务端读取信号并作出响应,然后回复客户端——以此循环,完成通信,——当双方各或某一方不想再继续通信,则关闭通信。

                                       网络编程(TCP/IP协议/套接字等)_第12张图片

3)TCP与UDP的主要区别(对比)

        网络编程(TCP/IP协议/套接字等)_第13张图片

那么我们为什么说TCP协议比UDP协议更加可靠呢?原因在于TCP具有有名的三次握手和四次分手。下面对于TCP的三次握手和四次分手进行介绍。

 

4)TCP的三次握手

第一次握手
当客户端向服务器发起连接请求时,客户端会发送同步序列标号SYN到服务器,在这里我们设SYN为x,等待服务器确认,这时客户端的状态为SYN_SENT。

第二次握手
当服务器收到客户端发送的SYN后,服务器要做的是确认客户端发送过来的SYN,在这里服务器发送确认包ACK,这里的ACK为x+1,意思是说“我收到了你发送的SYN了”,同时,服务器也会向客户端发送一个SYN包,这里我们设SYN为y。这时服务器的状态为SYN_RECV。
一句话,服务器端发送SYN和ACK两个包。

第三次握手
客户端收到服务器发送的SYN和ACK包后,需向服务器发送确认包ACK,“我也收到你发送的SYN了,我这就给你发个确认过去,然后我们即能合体了”,这里的ACK为y+1,发送完毕后,客户端和服务器的状态为ESTABLISH,即TCP连接成功。就可以进行数据信息的传输了。

在三次握手中,客户端和服务器端都发送两个包SYN和ACK,只不过服务器端的两个包是一次性发过来的,客户端的两个包是分两次发送的。

其中的关键内容:

两个包(服务端和客户端双方都会发送): 同步序列标号 SYN     确认包 ACK

四种状态

SYN_SENT(发送SYN报文) 、LISTEN(监听) 、 SYN_RECV(接收SYN报文) 、 ESTABLISHED(建立连接)

    网络编程(TCP/IP协议/套接字等)_第14张图片

X是任意数值。

       网络编程(TCP/IP协议/套接字等)_第15张图片

5)TCP四次分手

当A端和B端要断开连接时,需要四次握手,这里称为四次挥手。

断开连接请求可以由客户端发出,也可以由服务器端发出,在这里我们称A端向B端请求断开连接。

第一次挥手
A端向B端请求断开连接时会向B端发送一个带有FIN标记的报文段,这里的FIN是Finish的意思。

第二次挥手
B端收到A发送的FIN后,B段现在可能现在还有数据没有传完,所以B端并不会马上向A端发送FIN,而是先发送一个确认序号ACK,意思是说“你发的断开连接请求我收到了,但是我现在还有数据没有发完,请稍等一下呗”。

第三次挥手
当B端的事情忙完了,那么此时B端就可以断开连接了,此时B端向A端发送FIN序号,意思是这次可以断开连接了。

第四次挥手
A端收到B端发送的FIN后,会向B端发送确认ACK,然后经过两个MSL时长后断开连接。
MSL是Maximum Segment Lifetime,最大报文段生存时间,2个MSL是报文段发送和接收的最长时间

直白点的理解:

A:我要跟你分手
B:行你让我考虑几天我再考诉你
B:我考虑好了,分就分了吧
A:好的,再见

    网络编程(TCP/IP协议/套接字等)_第16张图片

其中关键点:

两个包:   FIN:Finish, ACK确认序号

6) TCP案例(代码实现)

 

服务端:
创建socket对象 ---- 绑定IP和端口 ---- 监听(有没有客户端来连接) ---- 建立连接(监听到有客户端连接) ---- 接收消息 ---- 发送消息 ---- 关闭
客户端:
创建socket对象 ---- 发起连接 ---- 发送消息 ---- 接收消息 ---- 关闭

"""服务端"""
import socket

# 1.创建socket对象
server = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
# 2.绑定地址和端口
server.bind(('0.0.0.0',9998))
# 3.监听是否有客户端连接 ,python2可以不传值,python3要传值
server.listen(5)   # 最多监听5个客户端
# 4.接收客户端的连接 accept返回两个值:跟服务端交流的socket对象;跟服务端交流的地址
client_socket_obj,client_addres = server.accept()
# 5.接收客户端发送的消息
recv_data = client_socket_obj.recv(1024)
print('接收到客户端发送的消息为:',recv_data.decode('utf-8')) # 发来的是bytes类型,解码成字符串
# 6.给客户端发送消息
send_data = b'hello client'
client_socket_obj.send(send_data)
# 7.关闭socket对象
client_socket_obj.close()
server.close()
"""客户端"""
import socket

# 1.创建socket对象
client = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
# 2.连接服务端
client.connect(('172.25.254.197',9998))
# 3. 给服务端发送消息
client.send(b'hello server')
# 4.接收服务端发送的消息
recv_data = client.recv(1024)
print('接收到服务端发送的消息为:',recv_data.decode('utf-8'))
# 5.关闭socket对象
client.close()


案例:实现(模拟QQ聊天)

"""服务端"""

import socket

# 1.创建socket对象
serverA = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
# 2.绑定地址和端口
serverA.bind(('0.0.0.0',9998))
print('QQ用户A上线.....')
serverA.listen(5)
# 4.接收客户端的连接 accept返回两个值:跟服务端交流的socket对象;跟服务端交流的地址
clientB_socket_obj,client_addres = serverA.accept()
while True:
    # 5.接收客户端发送的消息
    recv_data = clientB_socket_obj.recv(1024)
    print('B:',recv_data.decode('utf-8')) # 发来的是bytes类型,解码成字符串
    if recv_data == b'quit':
        print('聊天结束....')
        break
    # 6.给客户端发送消息
    send_data = input('A:').encode('utf-8')
    if not send_data:
        continue
    clientB_socket_obj.send(send_data)
# 7.关闭socket对象
clientB_socket_obj.close()
serverA.close()
"""客户端"""

import socket

# 1.创建socket对象
clientB = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
print('QQ用户B上线....')
# 2.连接服务端
clientB.connect(('172.25.254.197',9998))
while True:
    # 3. 给服务端发送消息
    send_data = input('B:').encode('utf-8')
    if not send_data:
        continue
    clientB.send(send_data)
    if send_data == b'quit':
        print('聊天结束....')
        break
    # 4.接收服务端发送的消息
    recv_data = clientB.recv(1024)
    print('A:',recv_data.decode('utf-8'))
# 5.关闭socket对象
clientB.close()

5、并发服务器

并发服务器是socket应用编程中最常见的应用模型。根据连接方式分为长连接和短连接.

通信方式

具体通信过程

长连接

建立SOCKET连接后不管是否使用都保持连接

短连接

双方有数据交互时,建立TCP连接,数据发送完成后断开连接

并发服务器模型根据处理方式可分为同步方式和异步方式。

                  网络编程(TCP/IP协议/套接字等)_第17张图片

还可分为单进程服务器和多进程服务器
单进程服务器:

同⼀时刻只能为⼀个客户进⾏服务,不能同时为多个客户服务
类似于找⼀个“明星”签字⼀样,客户需要耐⼼等待才可以获取到服务

多进程服务器:
通过为每个客户端创建⼀个进程的⽅式,能够同时为多个客户端进⾏服务
缺点: 当客户端不是特别多的时候,这种⽅式还⾏,如果有⼏百上千个,就不 可取了,因为每次创建进程等过程需要好较⼤的资源

多进程服务端实现:

#实现多进程:实例化对象,创建子类继承

# 任务: 处理客户端的请求并为其服务
def dealwithClient(clientB_socket_obj):
    while True:
        # 接收客户端发送的消息
        recv_data = clientB_socket_obj.recv(1024)
        print('B:', recv_data.decode('utf-8'))  # 发来的是bytes类型,解码成字符串
        if recv_data == b'quit':
            print('聊天结束....')
            break
        # 给客户端发送消息
        send_data = input('A:').encode('utf-8')
        if not send_data:
            continue
        clientB_socket_obj.send(send_data)
    clientB_socket_obj.close()

import socket
from multiprocessing import Process

# 创建socket对象
serverA = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
# 绑定地址和端口
serverA.bind(('0.0.0.0',9992))
# 监听是否有客户端连接
serverA.listen(5)

# 接收多次请求
while True:
    # 4.接收客户端的连接 accept返回两个值:跟服务端交流的socket对象;跟服务端交流的地址
    clientB_socket_obj,client_addres = serverA.accept()
    p = Process(target=dealwithClient,args=(clientB_socket_obj,))
    p.start()

多线程服务器:

        网络编程(TCP/IP协议/套接字等)_第18张图片

协程-TCP服务器

                    网络编程(TCP/IP协议/套接字等)_第19张图片

 

                           网络编程(TCP/IP协议/套接字等)_第20张图片

基于TCP多进程服务器

服务端:

​
# 实现多进程的方式:
#       1. 实例化对象
#       2. 继承子类
#       注意: 使用时一定要确定多进程要处理的任务


# 任务: 处理客户端请求并为其服务
def dealWithClient(clientSocketObj, clientAddress):
    while True:
        # 5. 接收客户端发送的消息
        recv_data = clientSocketObj.recv(1024).decode('utf-8')
        print(clientAddress[0] + str(clientAddress[1]) + ':> ' + recv_data)
        if recv_data == 'quit':
            break
    clientSocketObj.close()


import socket
from multiprocessing import Process

# 1. 创建服务端socket对象
server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

# 2. 绑定地址和端口(IP:port)
server.bind(('0.0.0.0', 9997))

# 3. 监听是否有客户端连接?listen
server.listen(5)
print('server start .........')

while True:
    # 4.接收客户端的连接accept
    clientSocketObj, clientAddress = server.accept()
    # dealWithClient(clientSocketObj)
    p = Process(target=dealWithClient, args=(clientSocketObj, clientAddress))
    p.start()

# server.close()

​

客户端:

import socket

# 1. 创建服务端socket对象
client = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)

# 2. 连接服务端
client.connect(('172.25.254.197', 9997))

while True:
    # 3.给服务端发送消息
    send_data = input('client: >> ').encode('utf-8')
    if not send_data:
        continue
    client.send(send_data)
    if send_data == 'quit':
        break

# 5. 关闭socket对象
client.close()

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(网络编程(TCP/IP协议/套接字等))