1. 网络基础
1.1 Python中的套接字
套接字的地址家族:address family,来自于unix;
旧一些的系统还可能称为域(domain)或者协议家族(protocol family),使用pf;
Python只支持AF_UNIX, AF_NETLINK, AF_TIPC, AF_INET家族。
1.2 面向连接的套接字:TCP
面向连接,就是通信之前先建立连接;
面向连接的通信,提供序列化,可靠和不重复的数据交付,而没有记录边界。
数据可以分成数据片,然后每片数据都能到达目的地;
使用的协议是传输控制协议(TCP),套接字类型必须是SOCK_STREAM;
1.3 无连接的套接字:UDP
通信之前,无需建立连接;数据有边界;
消息是整体发送的,但无法保证他的顺序性、可靠性和重复性。
使用的协议是用户数据报协议(UDP),套接字类型是SOCK_DGRAM,该名字来自于datagram数据报
1.4 IP地址的分类
每一个IP地址包括两部分:网络地址+主机地址
● A类地址:1个字节的网络地址+3个字节的主机地址,网络地址最高位必须是0.
● B类地址:2个字节的网络地址+2个字节的主机地址,网络地址最高位必须是10.
● C类地址:3个字节的网络地址+1个字节的主机地址,网络地址最高位必须是110.
● D类地址:第1个字节以1110开始,不用于网络,用于广播。
● E类地址:保留使用。
1.5 子网掩码
子网掩码,就是用来确定IP地址的网络号和主机号的。
子网掩码与IP地址一样,也是32位。
判断规则:
● 左边是网络位,用二进制数字1表示。
● 右边是主机位,用二进制数字0表示。
例子:
● 假设IP地址为192.168.1.1,子网掩码为255.255.255.0
● 那么,其中1有24个,代表与其对应的IP地址左边24位是网络号。
● 其中,0有8个,代表与其对应的IP地址的右边8位是主机号。
2.socket
2.1 socket
在 Python 中 使用socket模块的函数 socket 就可以完成
语法
import socket
socket.socket(AddressFamily, Type)
● 函数 socket.socket 创建一个 socket,该函数带有两个参数:
● Address Family:可以选择 AF_INET(用于 Internet 进程间通信) 或者AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
● Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)
UDP例子
import socket
def main():
# 创建一个udp套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 可以使用套接字收发数据
# udp_socket.sendto("hahahah", 对方的ip以及port)
udp_socket.sendto(b"hahahah------1----", ("192.168.33.53", 8080))
# 关闭套接字
udp_socket.close()
if __name__ == "__main__":
main()
2.2 套接字对象(內建)方法
服务器套接字方法
方法 |
描述 |
s.bind() |
将地址(主机名,端口号)绑定到套接字上; |
s.listen(backlog) |
设置并启动tcp监听;backlog就是监听的连接数; |
s.accept() |
被动接受tcp客户端连接,一致等待直到连接到达(阻塞);返回(套接字对象,客户端地址)组成的元组; |
客户端套接字方法
方法 |
描述 |
s.connect(address) |
主动发起tcp服务器连接;连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。 |
s.connect_ex() |
connect()的扩展版本,有问题时会以错误码的形式返回,而不是抛出异常; |
普通的套接字方法
方法 |
描述 |
s.recv(bufsize[, flag]) |
接受tcp消息;接受套接字的数据。数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。 |
s.recv_into() |
接受tcp消息到指定的缓冲区; |
s.send(string[, flag]) |
发送tcp消息;将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。 |
s.sendall(string[, flag]) |
完整的发送tcp消息;将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。 |
s.recvfrom(bufsize[, flag]) |
接受udp消息;与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。 |
s.recvfrom_into() |
接受udp消息到指定的缓冲区; |
s.sendto(string[, flag], address) |
发送udp消息;将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。 |
s.getpeername() |
得到连接到套接字(tcp)的远程地址;返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。 |
s.getsockname() |
得到当前套接字的地址;返回套接字自己的地址。通常是一个元组(ipaddr,port) |
s.getsockopt() |
返回给定套接字选项的值; |
s.setsockopt() |
设置给定套接字选项的值; |
s.shutdown() |
关闭连接; |
s.close() |
关闭套接字; |
s.detach() |
在未关闭文件描述符的情况下关闭套接字,返回文件描述符; |
s.ioctl() |
控制套接字的模式(仅支持windows); |
面向阻塞的套接字方法
方法 |
描述 |
s.setblocking() |
设置套接字的阻塞或非阻塞模式; |
s.settimeout(timeout) |
设置阻塞套接字操作的超时时间;设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect()) |
s.gettimeout() |
获取阻塞套接字操作的超时时间; |
面向文件的套接字方法
方法 |
描述 |
s.fileno() |
套接字的文件描述符; |
s.makefile() |
创建与套接字关联的文件对象; |
数据属性
方法 |
描述 |
s.family |
套接字家族; |
s.type |
套接字类型; |
s.proto |
套接字协议; |
2.3 socket模块属性
数据属性
● AF_UNIX, AF_INET, AF_INET6,AF_NETLINK, AF_TIPC: Python中支持的套接字地址家族;
● SOCK_STREAM, SOCK_DGRAM:套接字类型;
● has_ipv6:指示是否支持IPv6的布尔标记;
异常
● error:套接字相关错误;
● herror:主机和地址相关错误;
● gaierror:地址相关错误;
● timeout:超时时间;
2.4 函数
方法 |
描述 |
socket() |
以给定的地址家族,套接字类型和协议类型(可选)创建一个套接字类型; |
socketpair() |
以给定的地址家族,套接字类型和协议类型(可选)创建一对套接字类型; |
create_connection() |
接收一个地址(ip,端口号)对,返回套接字对象; |
fromfd() |
以一个打开的文件描述符创建一个套接字对象; |
ssl() |
通过套接字启动一个安全套接字层连接,不执行证书验证; |
getaddrinfo() |
获取一个五元组形式的地址信息; |
getnameinfo() |
给定一个套接字地址,返回(主机名,端口号)二元组; |
getfqdn() |
返回完整的域名; |
gethostname() |
返回当前主机名; |
gethostbyname() |
将一个主机名映射到它的ip地址; |
gethostbyname_ex() |
返回主机名,别名主机集合和ip地址列表; |
gethostbyaddr() |
将一个ip地址映射到DNS信息;返回gethostbyname_ex()相同的3元组; |
getprotobyname() |
将一个协议名(如tcp)映射到一个数字; |
getservbyname()/getservbyport() |
将一个服务名映射到一个端口号,或者反过来; |
ntohl()/ntohs() |
将来自网络的整数转换为主机字节顺序; |
htonl()/htons() |
将来自主机的整数转换成网络字节顺序; |
inet_aton()/inet_ntoa() |
将ip地址八进制字符转换成32位格式,或者反过来(仅限于IPv4); |
inet_pton()/inet_ntop() |
将ip地址字符串转换成打包的二进制格式,或者反过来; |
getdefaulttimeout()/setdefaulttimeout() |
以秒(浮点数)为单位返回/设置默认套接字超时时间; |
3. UPD
3.1 UDP-用户数据报协议
● 由于UDP是无连接的,服务器只需要等待接入即可。
● 无连接的socket类型是SOCK_DGRAM;
● UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。
● 由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
UDP的服务端和客户端没有明显的区别;
● 服务端会bind()地址和端口;然后先recvfrom(),再sendto();
● recvfrom()函数:返回两部分,数据+ip。
● 客户端会先sendto()到服务端的IP和port,然后在recvfrom()得到服务端返回的数据;
● UDP每次发送数据,都会有IP和端口。
UDP网络程序的流程图
● 创建一个UDP客户端程序的流程如下:
● 1.创建客户端套接字(服务端)
● 2.发送/接受数据
● 3.关闭套接字
import socket
def main():
# 创建一个udp套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 从键盘获取数据
send_data = input("请输入要发送的数据:")
# 可以使用套接字收发数据
# udp_socket.sendto("hahahah", 对方的ip以及port)
# udp_socket.sendto(b"hahahah------1----", ("192.168.33.53", 8080))
udp_socket.sendto(send_data.encode("utf-8"), ("192.168.33.53", 8080))
# 关闭套接字
udp_socket.close()
if __name__ == "__main__":
main()
3.2 udp网络程序-发送、接收数据
#coding=utf-8
from socket import *
# 1. 创建udp套接字
udp_socket = socket(AF_INET, SOCK_DGRAM)
# 2. 准备接收方的地址
dest_addr = ('192.168.236.129', 8080)
# 3. 从键盘获取数据
send_data = input("请输入要发送的数据:")
# 4. 发送数据到指定的电脑上
udp_socket.sendto(send_data.encode('utf-8'), dest_addr)
# 5. 等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数
# 6. 显示对方发送的数据
# 接收到的数据recv_data是一个元组
# 第1个元素是对方发送的数据
# 第2个元素是对方的ip和端口
print(recv_data[0].decode('gbk'))
print(recv_data[1])
# 7. 关闭套接字
udp_socket.close()
3.3 UPD服务端、客户端
服务端:
● 先通过recvfrom()一直接收来自于客户端的连接;返回了服务端的数据和地址;
● 在通过sendto()向客户端发送数据
#!/usr/bin/env python
#coding:utf-8
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 使用SOCK_DGRAM代表UDP的套接字类型
s.bind(("127.0.0.1", 8885)) # UDP的服务器只需要绑定地址即可等待客户端的接入
while True:
data, address = s.recvfrom(1024) # UDP的服务端处于接收状态,得到数据和地址
print data
print address
s.sendto("hello UDP", address) # 向地址发送数据
客户端
● 先通过sendto()发送数据到服务端;
● 在通过recvfrom()从服务端接收数据;返回的是数据和地址;
● 如果只是客户端,是不需要绑定(bind())端口的,因为客户端只要写了目的的ip和端口,就可以给目标程序发数据。
● 注意:下面的程序可以在Python2中运行;
● 如果是Python3的话,需要在sendto中的要发送的数据前面添加一个b,即c.sendto(b’hello UDPsERVER’, addr);
● Python3,还可以通过sendData.encode(‘utf-8’)编码成utf-8去发送。得到数据以后,需要通过recvData.decode(‘utf-8’)来解码
#!/usr/bin/env python
#coding:utf-8
import socket
c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
addr = ("127.0.0.1", 8885)
c.sendto("hello UDPsERVER", addr) # 向服务端发送数据
data, address = c.recvfrom(1024) # 从服务端接收数据
print data
print address
3.4 一个聊天程序
import socket
def send_msg(udp_socket):
"""获取键盘数据,并将其发送给对方"""
# 1. 从键盘输入数据
msg = input("n请输入要发送的数据:")
# 2. 输入对方的ip地址
dest_ip = input("n请输入对方的ip地址:")
# 3. 输入对方的port
dest_port = int(input("n请输入对方的port:"))
# 4. 发送数据
udp_socket.sendto(msg.encode("utf-8"), (dest_ip, dest_port))
def recv_msg(udp_socket):
"""接收数据并显示"""
# 1. 接收数据
recv_msg = udp_socket.recvfrom(1024)
# 2. 解码
recv_ip = recv_msg[1]
recv_msg = recv_msg[0].decode("utf-8")
# 3. 显示接收到的数据
print(">>>%s:%s" % (str(recv_ip), recv_msg))
def main():
# 1. 创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2. 绑定本地信息
udp_socket.bind(("", 7890))
while True:
# 3. 选择功能
print("="*30)
print("1:发送消息")
print("2:接收消息")
print("="*30)
op_num = input("请输入要操作的功能序号:")
# 4. 根据选择调用相应的函数
if op_num == "1":
send_msg(udp_socket)
elif op_num == "2":
recv_msg(udp_socket)
else:
print("输入有误,请重新输入...")
if __name__ == "__main__":
main()
3.5 UDP广播
● 只有UDP广播,TCP没有广播
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket, sys
dest = ('<broadcast>', 7788) # <broadcast> 自动识别广播地址
# 创建udp套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 对这个需要发送广播数据的套接字进行修改设置,否则不能发送广播数据
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST,1)
# 以广播的形式发送数据到本网络的所有电脑中
s.sendto("Hi".encode('utf-8'), dest)
print ("等待对方回复(按ctrl+c退出)")
while True:
(buf, address) = s.recvfrom(2048)
print ("Received from %s: %s" % (address, buf))
5. TCP
5.1 TCP介绍
● TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。
● TCP通信需要经过创建连接、数据传送、终止连接三个步骤。
5.2 TCP特点
面向连接
● 通信双方必须先建立连接才能进行数据的传输,双方都必须为该连接分配必要的系统内核资源,以管理连接的状态和连接上的传输。
● 双方间的数据传输都可以通过这一个连接进行。
● 完成数据交换后,双方必须断开此连接,以释放系统资源。
● 这种连接是一对一的,因此TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议
可靠传输
● TCP采用发送应答机制
● TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功
● 超时重传
● 发送端发出一个报文段之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段。
● TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。
● 错误校验
● TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
● 流量控制和阻塞管理
● 流量控制用来避免主机发送得过快而使接收方来不及完全收下。
5.3 TCP与UDP的不同点
● 面向连接(确认有创建三方交握,连接已创建才作传输。)
● 有序数据传输
● 重发丢失的数据包
● 舍弃重复的数据包
● 无差错的数据传输
● 阻塞/流量控制
5.4 TCP客户端、服务端
客户端
● 创建socket套接字
● 通过connect方法连接服务器端IP和端口
● recv/send接收发送数据
from socket import *
# 创建socket
tcp_client_socket = socket(AF_INET, SOCK_STREAM)
# 目的信息
server_ip = input("请输入服务器ip:")
server_port = int(input("请输入服务器port:"))
# 链接服务器
tcp_client_socket.connect((server_ip, server_port))
# 提示用户输入数据
send_data = input("请输入要发送的数据:")
tcp_client_socket.send(send_data.encode("gbk"))
# 接收对方发送过来的数据,最大接收1024个字节
recvData = tcp_client_socket.recv(1024)
print('接收到的数据为:', recvData.decode('gbk'))
# 关闭套接字
tcp_client_socket.close()
服务端
● socket创建一个套接字
● bind绑定ip和port
● listen使套接字变为可以被动链接
● accept等待客户端的链接
● recv/send接收发送数据
from socket import *
# 创建socket
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
# 本地信息
address = ('', 7788)
# 绑定
tcp_server_socket.bind(address)
# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的链接了
tcp_server_socket.listen(128)
# 如果有新的客户端来链接服务器,那么就产生一个新的套接字专门为这个客户端服务
# client_socket用来为这个客户端服务
# tcp_server_socket就可以省下来专门等待其他新客户端的链接
client_socket, clientAddr = tcp_server_socket.accept()
# 接收对方发送过来的数据
recv_data = client_socket.recv(1024) # 接收1024个字节
print('接收到的数据为:', recv_data.decode('gbk'))
# 发送一些数据到客户端
client_socket.send("thank you !".encode('gbk'))
# 关闭为这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了,如果还需要服务,只能再次重新连接
client_socket.close()
5.5 tcp注意点
● tcp服务器一般情况下都需要绑定,否则客户端找不到这个服务器
● tcp客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的ip、port等信息就好,本地客户端可以随机
● tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动的,这是做tcp服务器时必须要做的
● 当客户端需要链接服务器时,就需要使用connect进行链接,udp是不需要链接的而是直接发送,但是tcp必须先链接,只有链接成功才能通信
● 当一个tcp客户端连接服务器时,服务器端会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务
● listen后的套接字是被动套接字,用来接收新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的
● 关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器,但是之前已经链接成功的客户端正常通信。
● 关闭accept返回的套接字意味着这个客户端已经服务完毕
● 当客户端的套接字调用close后,服务器端会recv解堵塞,并且返回的长度为0,因此服务器可以通过返回数据的长度来区别客户端是否已经下线
5.6 TCP短连接、长连接
TCP短连接
● 模拟一种TCP短连接的情况:
● client 向 server 发起连接请求
● server 接到请求,双方建立连接
● client 向 server 发送消息
● server 回应 client
● 一次读写完成,此时双方任何一个都可以发起 close 操作
● 在步骤5中,一般都是 client 先发起 close 操作。当然也不排除有特殊的情况。
● 从上面的描述看,短连接一般只会在 client/server 间传递一次读写操作
TCP长连接
● 模拟一种长连接的情况:
client 向 server 发起连接
● server 接到请求,双方建立连接
● client 向 server 发送消息
● server 回应 client
● 一次读写完成,连接不关闭
● 后续读写操作…
● 长时间操作之后client发起关闭请求
5.7 文件下载例子
client.py
import socket
def main():
# 1. 创建套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 获取服务器的ip port
dest_ip = input("请输入下载服务器的ip:")
dest_port = int(input("请输入下载服务器的port:"))
# 3. 链接服务器
tcp_socket.connect((dest_ip, dest_port))
# 4. 获取下载的文件名字
download_file_name = input("请输入要下载的文件名字:")
# 5. 将文件名字发送到服务器
tcp_socket.send(download_file_name.encode("utf-8"))
# 6. 接收文件中的数据
recv_data = tcp_socket.recv(1024) # 1024--->1K 1024*1024--->1k*1024=1M 1024*1024*124--->1G
if recv_data:
# 7. 保存接收到的数据到一个文件中
with open("[新]" + download_file_name, "wb") as f:
f.write(recv_data)
# 8. 关闭套接字
tcp_socket.close()
if __name__ == "__main__":
main()
server.py
import socket
def send_file_2_client(new_client_socket, client_addr):
# 1. 接收客户端 需要下载的文件名
# 接收客户端发送过来的 要下载的文件名
file_name = new_client_socket.recv(1024).decode("utf-8")
print("客户端(%s)需要下载文件是:%s" % (str(client_addr), file_name))
file_content = None
# 2. 打开这个文件,读取数据
try:
f = open(file_name, "rb")
file_content = f.read()
f.close()
except Exception as ret:
print("没有要下载的文件(%s)" % file_name)
# 3. 发送文件的数据给客户端
if file_content:
# new_client_socket.send("hahahghai-----ok-----".encode("utf-8"))
new_client_socket.send(file_content)
def main():
# 1. 买个手机(创建套接字 socket)
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 插入手机卡(绑定本地信息 bind)
tcp_server_socket.bind(("", 7890))
# 3. 将手机设置为正常的 响铃模式(让默认的套接字由主动变为被动 listen)
tcp_server_socket.listen(128)
while True:
# 4. 等待别人的电话到来(等待客户端的链接 accept)
new_client_socket, client_addr = tcp_server_socket.accept()
# 5. 调用发送文件函数,完成为客户端服务
send_file_2_client(new_client_socket, client_addr)
# 6. 关闭套接字
new_client_socket.close()
tcp_server_socket.close()
if __name__ == "__main__":
main()
6. SocketServer模块
6.1 介绍
● SocketServer模块是标准库中的一个高级模块,Python 3.x中重命名为socketserver;
● 事件驱动的;
6.2 SocketServer 模板类
类 |
说明 |
BaseServer |
包含核心服务器功能和min-in类的钩子;仅用于推导,不会创建这个类的实例;可以使用TCPServer或UDPServer创建类的实例; |
TCPServer/UDPServer |
基础的网络同步TCP/UDP服务器; |
UnixStreamServer/UnixDatagramServer |
基本的基于文件同步 TCP/UDP 服务器 |
ForkingMixIn/ThreadingMixIn |
实现了核心的进程化或线程化的功能,用于与服务器类进行混合,以提供一些异步特性。不要直接生成这个类的对象; |
ForkingTCPServer/ForkingUDPServer |
ForkingMixIn和TCPServer/UDPServer的组合; |
ThreadingTCPServer/ThreadingUDPServer |
ThreadingMixIn和TCPServer/UDPServer的组合; |
BaseRequestHandler |
包含处理服务请求的核心功能,无法创建该类实例;可以使用StreamRequestHandler/DatagramRequestHandler创建类的实例; |
StreamRequestHandler/DatagramRequestHandler |
实现TCP/UDP服务器的服务处理器; |
6.3 例子
服务端
#!/usr/bin/env python
#coding:utf-8
from SocketServer import(TCPServer as TCP, StreamRequestHandler as SRH)
from time import ctime
HOST="127.0.0.1"
PORT =8876
ADDR =(HOST, PORT)
# 定义一个处理类,继承了StreamRequestHandler类,且重写了handler()方法
# 当有客户端连接的时候,就会调用handle()进行处理
classMyRequestHandler(SRH):
defhandle(self):
print("来自于: ", self.client_address, self.wfile.write("hello world client"))
# print ("来自于: ", self.client_address, self.wfile.write("[%s] %s" % (ctime(), self.rfile.readline())))
tcpSer = TCP(ADDR, MyRequestHandler)
print("等待连接...")
tcpSer.serve_forever()
客户端
#!/usr/bin/env python
#coding:utf-8
import socket
HOST="127.0.0.1"
PORT =8876
ADDR =(HOST, PORT)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 创建socket对象
s.connect(ADDR)# 连接到socket
data = s.recv(1024)# 接收服务端返回的数据
print data
实现异步多线程服务端
/*实现异步多线程服务端,直接使用上面的client.py两种结合运行就可以了*/
#!/usr/bin/env python
#coding:utf-8
import SocketServer
class MyServer(SocketServer.BaseRequestHandler):
def setup(self):
pass
def handle(self):
conn = self.request
conn.send("hello") #向客户端发送数据
flag = True
while flag: #为了一直等待接受客户端发送的数据
data = conn.recv(1024)
print data
if data == "exit":
flag = False
conn.send("sb")
conn.close()
def finish(self):
pass
if __name__ == "__main__":
server = SocketServer.ThreadingTCPServer(('127.0.0.1', 8882), MyServer)
server.serve_forever()
原文始发于微信公众号(Python之家):Python基础-25-网络编程
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/198463.html