一、网络通信概述
1、网络是什么?
- 简单意义上来说,网络就是⼀种辅助双⽅或者多⽅能够连接在⼀起的⼯具。
- 官方对于网络的定义为: 网络是由若干节点和连接这些节点的链路构成,表示诸多对象及其相互联系。
2.使用网络的目的
- 联通多⽅然后进⾏通信⽤的,即把数据从⼀⽅传递给另外⼀⽅;
- ⽤⽹络能够把多⽅链接在⼀起,然后可以进⾏数据传递;
- ⽹络编程就是,让在不同的电脑上的软件能够进⾏数据传递,即进程之间的通信。
二、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分层协议
1)TCP/IP分层协议
TCP/IP参考模型是首先由ARPANET所使用的网络体系结构,共分为四层(个别参考把其分为5层):网络接口层(又称链路层和物理层)、网络层(又称互联层)、传输层和应用层, 每一层都呼叫它的下一层所提供的网络来完成自己的需求。
(1)每一层对应的协议有(TCP/IP协议族):
- 应用层协议(第一层):FTP(File Transfer Protocol,文件传输协议)、TELNET(用户远程登录服务协议)、DNS(Domain Name Service,是域名解析服务)、SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)、NFS(Network File System,网络文件系统)、HTTP(Hypertext Transfer Protocol,超文本传输协议)。
- 传输层协议(第二层): TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram protocol,用户数据报协议)。
- 网络层协议(第三层):IP(Internet Protocol,英特网协议)、ICMP(Internet Control Message Protocol,控制报文协议)、ARP(Address Resolution Protocol,地址转换协议)、RARP(Reverse ARP,反向地址转换协议)。
- 网络接口层协议(第四层):Ethernet 802.3、Token Ring 802.5、X.25、Frame relay、HDLC、PPP ATM等。
(2)TCP/IP协议各层的功能:
- 第一层是应用层,功能是服务于应用进程的,就是向用户提供数据加上编码和对话对的控制。
- 第二层是运输层,功能是能够解决诸如端到端可靠性和保证数据按照正确的顺序到达。包括所给数据应该送给哪个应用程序。
- 第三层是网络层,功能是进行网络连接的建立,和终止及IP地址的寻找最佳途径等功能。
- 第四层是网络接口层,功能是传输数据的物理媒介,是数据包从一个设备的网络层传输到另外一个设备的网络层的方法。还有控制组成网络的硬件设备。
2)IP地址
(1)定义
IP地址是一种在Internet上的给主机编址的方式,也称为网际协议地址。
(2)作用
⽤来在⽹络中标记⼀台电脑的⼀串数字,⽐如192.168.1.1;在本地局域⽹上是惟⼀的。
(3)分类
每⼀个IP地址包括两部分:⽹络地址和主机地址 ,有如下几种类型:
i . 私有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
ii.回环地址IP
- IP地址127.0.0.1 代表本机IP地址,等价于localhost, ⽤ http://127.0.0.1 就可以测试本机中配置的Web服务器。
- 127.0.0.1,通常被称为本地回环地址(Loop back address),不属于任何一个有类别地址类。它代表设备的本地虚拟接口,所以默认被看作是永远不会宕掉的接口。在windows操作系统中也有相似的定义,所以通常在不安装网卡前就可以ping通这个本地回环地址。一般都会用来检查本地网络协议、基本数据接口等是否正常的。
3)子网掩码
(1)定义
⼦⽹掩码(Net mask)不能单独存在,它必须结合IP地址⼀起使⽤。
(2)作用
将某个IP地址划分成⽹络地址和主机地址两部分。
(3)设定规则
⼦⽹掩码的设定必须遵循⼀定的规则, 用来判断两个IP是否在同一个网络。
A:172.25.254.18/24
B:172.25.0.10/24
由此可知,A、B不在同一个网络
4)端口
- 端⼝就像⼀个房⼦的⻔,是出⼊这间房⼦的必经之路;
- 端⼝号只有整数,范围是从0到65535。
- 唯一标识一个计算机中的进程
下面是一些常用的服务及端口号:
HTTP协议 | 80/8080/3128/8081/9098 |
---|---|
FTP文件传输 | 21 |
SSH安全登录 | 22/tcp |
SCP文件传输 | 22/tcp |
Telnet远程登录 | 23 |
SMTP简单邮件传输协议 | 25 |
pop3 | 110/tcp |
SOCKS | 1080 |
HTTP服务器 | 80/tcp(木马Executor开放此端口) |
HTTPS | 443/tcp 443/udp |
Oracle | 1521 |
MySQL | 3306 |
redis | 6379 |
linux中如何查看端口呢?
- 在命令行输入:cat /etc/services | less
- 然后在出现的页面下方输入要查询的服务,回车
即可查看所需要的查看的服务的端口。
三、socket编程
1、为什么需要socket?
- 通过之前的学习, 我们知道本地间通信(IPC)有队列、同步(互斥锁、条件变量等)、以及管道等方法。
- 但是不同主机之间如果需要通信,则就需要用到socakt.
- 问题: 本地通过进程PID来唯⼀标识⼀个进程,在⽹络中如何唯⼀标识⼀个进程?
- 答: 网络层的“IP地址”可以唯⼀标识⽹络中的主机,⽽传输层的“协议+端⼝”可以唯⼀标识主机中的应⽤程序(进程)。因此利用IP地址,协议,端⼝就可以标识⽹络的进程。
2.什么是socket?
- 套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。
- 套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。
- 网络套接字是IP地址与端口的组合。
简单来说:socket(简称套接字) 是进程间通信的⼀种⽅式, 能实现不同主机间的进程间通信,我们⽹络上各种各样的服务⼤多都是基于 Socket 来完成通信的。
比如以下服务等都是基于socket 来完成通信的。
3.创建socket
在 Python 中 使⽤socket 模块的函数 socket 就可以完成:
socket.socket(AddressFamily, Type)
- Address Family: 网络协议地址
AF_INET: IPV4⽤于 Internet 进程间通信
AF_INET6: IPV6⽤于 Internet 进程间通信 - Type:套接字类型
SOCK_STREAM: 流式套接字,主要⽤于 TCP 协议 SOCK_DGRAM: 数据报套接字,主要⽤于 UDP 协 议
import socket
#1.创建socket对象
# family: AF_INET(TPV4) AF_INET6(IPV6) ======网络层协议
# type: #SOCK_STREAM(TCP) SOCK_DGRAM (UDP) =====传输层协议
# Linux系统中,socket可以认为是一个文件
#socketObj=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
#print(socketObj.getsockname())
#2.关闭socket对象
#socketObj.close()
#3.socket基本使用
import os
os.system('hostname')#os.system执行linux命令
hostname=socket.gethostname()
print('主机名:',hostname)
print(socket.gethostbyname('localhost'))
运行结果
LAPTOP-C0H3VQGK
主机名: LAPTOP-C0H3VQGK
127.0.0.1
小练习如下:
- 创建⼀个tcp socket(tcp套接字)
把代码中的Type:套接字类型写成 SOCK_STREAM - 创建⼀个udp socket(udp套接字)
把代码中的Type:套接字类型写成 SOCK_DGRAM 即可
四、socket中的UDP与TCP
1.UDP
1)什么是UDP?
- UDP ⽤户数据报文协议(User Data Protocol),是⼀个无连接的简单的⾯向数据报文的运输层(传输层)协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达⽬的地。
- 由于UDP在传输数据报前不⽤在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
- UDP是⼀种面向无连接的协议,每个数据报都是⼀个独立的信息,包括完整的源地址和目的地址,它在⽹络上以任何可能的路径传往⽬的地,因此能否到达⽬的地,到达⽬的地的时间以及内容的正确性都是不能被保证的。
2)UDP的特点
- UDP是面向无连接的通讯协议,UDP数据包括⽬的端口号和源端口号信息, 由于通讯不需要连接,所以可以实现⼴播发送。
- UDP传输数据时有大小限制,每个被传输的数据报必须限定在64KB之内(约为2^32-1)。
- UDP是⼀个不可靠的协议,发送⽅所发送的数据报并不⼀定以相同的次序到达接收⽅。
下图为一个UDP数据报文的结构:
3)UDP应用场景
UDP是⾯向消息的协议,通信时不需要建⽴连接,数据的传输⾃然是不可靠 的,UDP⼀般⽤于多点通信和实时的数据业务。
比如:
- 语⾳⼴播
- 视频
- TFTP(简单⽂件传送协议)
- SNMP(简单⽹络管理协议)
- DNS(域名解释(域名服务器Domain Name Server))等等
4)UDP网络程序
i.通过UDP通信服务的过程:
- 服务端:给别人提供服务/报文的端口
客户端:接收服务端服务/报文的端口
- 无论是服务端还是客户端,首先建立一个socket() 对象将来进行通信;
- 服务端等待客户端的报文消息,服务端的bind(),用来绑定服务端的一个IP或一个端口;
- 客户端:sendto() 客户端想要给服务端发消息,由于UDP是无连接的,所以客户端不需要通知服务端,直接发送就好了;
- 服务端recvfrom() 客户端发送消息后,服务端接收消息;
- 服务端sendto() 服务端接收消息后,最做出一个响应给客户端;
- 客户端recvfrom() 客户端接收服务端发出的响应,这样就完成一次通信;
- 客户端close() 客户端决定不再发消息时,结束socket()对象(同样服务端不想接收消息时,也可以结束自己的socket()对象)。
ii .图解:![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/0949d5caed5b88efdeb36065eaead37a.png)
iii. 项目测试:
- 服务端(UDP Server ):提供服务
创建socket()对象—绑定接收消息的IP和端口bind()—接收消息recvfrom()—发送响应sendto()—关闭socket对象 - 客户端(UDP Client):访问提供的服务
创建socket()对象—发送消息sendto()—接收响应recvfrom()—关闭socket()对象
同一个目录下创建两个.py文件:服务端.py,客户端.py
服务端:
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()
运行结果
等待客户端UDP的连接...
接收到的客户端的数据为: hello Server
客户端
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.111',9001))#发给哪台主机的哪个端口
#3.接收服务端的响应信息
recvdata,address=udpClient.recvfrom(1024)
print('接收到的服务端的消息为:',recvdata.decode('utf-8'))
#4.关闭socket对象
udpClient.close()
运行结果
接收到的服务端的消息为: hello client
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',9001))
print('等待客户端连接。。。。')
while True:
# 返回的是一个元组,每个元素的客户端发送的信息,第二个元素是客户端和服务端交互的地址(IP,端口)
recvdata,address=udpserver.recvfrom(1024)
print('B:>>',recvdata.decode('utf-8'))
if recvdata==b'quit':
print('聊天结束....')
break
senddata=input('A:>>').encode('utf-8')
if not senddata:
continue
udpserver.sendto(senddata,address)
udpserver.close()
客户端:
import socket
udpClient=socket.socket(family=socket.AF_INET,type=socket.SOCK_DGRAM)
print('QQ用户B上线....')
while True:
senddata=input('B:>>').encode('utf-8')
if not senddata:
continue
udpClient.sendto(senddata,('192.168.1.111',9001))
if senddata==b'quit':
print('聊天结束。。。')
break
recedata,address=udpClient.recvfrom(1024)
print('A:>>',recedata.decode('utf-8'))
udpClient.close()
运行结果
#服务端:
等待客户端连接。。。。
B:>> hello
A:>>hi
B:>> 吃饭了吗
A:>>还没有呀,你呢
B:>> 我在吃拉
A:>>quit
B:>> quit
聊天结束....
#客户端:
QQ用户B上线....
B:>>hello
A:>> hi
B:>>吃饭了吗
A:>> 还没有呀,你呢
B:>>我在吃拉
A:>> quit
B:>>quit
聊天结束。。。
2.TCP
1)什么是TCP
TCP: 传输控制协议(Transmission Control Protocol,缩写为TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP协议具有的特点:
- 基于流的方式;
- 面向连接;
- 可靠通信方式;
- 在网络状况不佳的时候尽量降低系统由于重传带来的带宽开销;
- 通信连接维护是面向通信的两个端点的,而不考虑中间网段和节点
2)TCP网络程序
TCP协议通信的大致过程: 首先,服务端和客户端都需要先建立socket()对象——服务端绑定IP和端口——服务端进行监听(为了保证有客户端和服务端进行连接)—— 监听结束如果有客户端和服务端连接,则可允许客户端建立连接(accept())——客户端发出连接信号——服务端读取信号并作出响应,然后回复客户端——以此循环,完成通信,——当双方各或某一方不想再继续通信,则关闭通信。
3)TCP与UDP的主要区别(对比)
TCP | UDP | |
---|---|---|
可靠性 | 可靠 | 不可靠 |
连接性 | 面向连接 | 无连接 |
报文 | 面向字节流 | 面向报文 |
效率 | 传输效率低 | 传输效率高 |
双工性 | 全双工 | 一对一、一对多、多对一、多对多 |
流量控制 | 有(滑动窗口) | 无 |
拥塞控制 | 有(慢开始、拥塞避免、快重传、快恢复) | 无 |
那么我们为什么说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(客户端分两次发送,服务端一次发送)
四种状态: LISTEN(监听)、SYN_SENT(发送SYN报文) 、 SYN_RECV(接收SYN报文) 、 ESTABLISHED(建立连接)
5)TCP四次分手
断开连接请求可以由客户端发出,也可以由服务器端发出,在这里我们称A端向B端请求断开连接。
当A端和B端要断开连接时,需要四次握手,这里称为四次分手。
- 第一次分手
A端向B端请求断开连接时会向B端发送一个带有FIN标记的报文段(seq=x+2)和一个确认序号ACK(y+1),这里的FIN是Finish的意思。 - 第二次分手
B端收到A发送的FIN后,B段现在可能现在还有数据没有传完,所以B端并不会马上向A端发送FIN,而是先发送一个确认序号ACK(x+3),意思是说“你发的断开连接请求我收到了,但是我现在还有数据没有发完,请稍等一下呗”。 - 第三次分手
当B端的事情忙完了,那么此时B端就可以断开连接了,此时B端向A端发送FIN序号(seq=y+1),意思是这次可以断开连接了。 - 第四次分手
A端收到B端发送的FIN后,会向B端发送确认ACK(y+2),然后经过两个MSL时长后断开连接。
MSL是Maximum Segment Lifetime,最大报文段生存时间,2个MSL是报文段发送和接收的最长时间
两个包: FIN:Finish, ACK确认序号
6)TCP案例
服务端:
创建socket对象—绑定IP和端口—监听(有没有客户端来连接)—建立连接(监听到有客户端来连接)—接收消息—发送消息—关闭
客户端:
创建socket对象—发起连接—发送消息—接收消息—关闭
i.通信测试
服务端:
import socket
#1.创建socket对象
server=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
#2.绑定IP地址和端口
server.bind(('0.0.0.0',9999))
#3.监听是否有客户端连接,python2可以不传值,python要传值
server.listen(5)#最多监听5个客户端
#4.接收客户端的连接, accept返回两个值:与服务端交流的socket对象,与服务端交流的地址
client_socket_obj,client_address=server.accept()
#5.接收客户端发送的消息
recvdata=client_socket_obj.recv(1024)
print('接收到客户端发送的消息为:',recvdata.decode('utf-8'))
#6.给客户端发送消息
senddata=b'hello client'
client_socket_obj.send(senddata)
#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(('192.168.1.111',9999))
#3.给服务端发送消息
client.send(b'hello server')
#4.接收服务端发送的消息
recvdata=client.recv(1024)
print('接收到服务端发送的消息为:',recvdata.decode('utf-8'))
#5.关闭socket对象
client.close()
运行结果
#服务端:
接收到客户端发送的消息为: hello server
#客户端
接收到服务端发送的消息为: hello client
ii.案例:模拟QQ聊天
服务端:
import socket
#1.创建socket对象
serverA=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
#2.绑定IP地址和端口
serverA.bind(('0.0.0.0',9998))
print('QQ用户A上线。。。。')
#3.监听是否有客户连接
serverA.listen(5)
#4.监听到有客户连接, accept返回两个值,分别是监听到的要连接的socket对象和它的地址
clientB,clientB_address=serverA.accept()
while True:
#5.接收客户B发送的消息
recvdata=clientB.recv(1024)
print('B:',recvdata.decode('utf-8'))
if recvdata==b'quit':
print('聊天结束...')
break
#6.给客户B发送消息
senddata=input('A:').encode('utf-8')
if not senddata:
continue
clientB.send(senddata)
#7.关闭socket对象
clientB.close()
serverA.close()
客户端:
import socket
#1.创建socket对象
client=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
#2.连接服务端
client.connect(('192.168.1.111',9999))
#3.给服务端发送消息
client.send(b'hello server')
#4.接收服务端发送的消息
recvdata=client.recv(1024)
print('接收到服务端发送的消息为:',recvdata.decode('utf-8'))
#5.关闭socket对象
client.close()
运行结果
#服务端A
QQ用户A上线。。。。
B: hello
A:haha
B: quit
聊天结束...
#客户端B
QQ用户B上线.....
B:hello
A: haha
B:quit
五、并发服务器
并发服务器是socket应用编程中最常见的应用模型。
1.分类
1).根据连接方式划分
根据连接方式分为长连接和短连接.
通信方式 | 具体通信过程 |
---|---|
长连接 | 建立SOCKET连接后不管是否使用都保持连接 |
短连接 | 双方有数据交互时,建立TCP连接,数据发送完成后断开连接 |
2).根据处理方式划分
并发服务器模型根据处理方式可分为同步方式和异步方式。
3).根据客户个数划分
单进程服务器:
- 同⼀时刻只能为⼀个客户进⾏服务,不能同时为多个客户服务
- 类似于找⼀个“明星”签字⼀样,客户需要耐⼼等待才可以获取到服务
多进程服务器:
- 通过为每个客户端创建⼀个进程的⽅式,能够同时为多个客户端进⾏服务
- 缺点: 当客户端不是特别多的时候,这种⽅式还⾏,如果有⼏百上千个,就不可取了,因为每次创建进程等过程需要耗费较⼤的资源
2.多进程服务器
案例实现:
#任务:处理客户端请求并为其服务
def dealwithClient(clientB):
while True:
# 5.接收客户B发送的消息
recvdata = clientB.recv(1024)
print('B:', recvdata.decode('utf-8'))
if recvdata == b'quit':
break
# 6.给客户B发送消息
senddata = input('A:').encode('utf-8')
if not senddata:
continue
clientB.send(senddata)
clientB.close()
import socket
from multiprocessing import Process
#创建socket对象
serverA=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
#绑定IP地址和端口
serverA.bind(('0.0.0.0',9998))
#监听是否有客户连接
serverA.listen(5)
print('server start ....')
while True:
#监听到有客户连接,
clientB,clientB_address=serverA.accept()
#dealwithClient(clientB)
p=Process(target=dealwithClient,args=(clientB,))
p.start()
3.多线程服务器
基于TCP多进程服务器
服务端:
#任务:处理客户端请求并为其服务
def dealwithClient(clientB,clientB_address):
while True:
# 5.接收客户B发送的消息
recvdata = clientB.recv(1024)
print(clientB_address[0]+str(clientB_address[1])+':>'+recvdata.decode('utf-8'))
if recvdata == b'quit':
break
# 6.给客户B发送消息
senddata = input('A:').encode('utf-8')
if not senddata:
continue
clientB.send(senddata)
clientB.close()
import socket
from multiprocessing import Process
#创建socket对象
serverA=socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
#绑定IP地址和端口
serverA.bind(('0.0.0.0',9956))
#监听是否有客户连接
serverA.listen(5)
print('server start ....')
while True:
#监听到有客户连接,
clientB,clientB_address=serverA.accept()
#dealwithClient(clientB)
p=Process(target=dealwithClient,args=(clientB,clientB_address))
p.start()
客户端:
import socket
# 1. 创建服务端socket对象
clientB = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# 2. 连接服务端
clientB.connect(('192.168.1.111', 9956))
while True:
# 3.给服务端发送消息
send_data = input('clientB: >> ').encode('utf-8')
if not send_data:
continue
clientB.send(send_data)
if send_data == 'quit':
break
# 5. 关闭socket对象
clientB.close()