文章目录
- 一些网络知识
- 什么是socket
- socket内置的方法
- 一个简单的socket案例
- socket粘包的概念
- socketserver(进阶)
- 开发的过程遇到的坑以及心得
- 待更新
一些网络知识
啥是DDOS攻击(洪水攻击),就是一些机器通过伪造IP地址头,不断的去访问(攻击)一个网站,导致网站的崩溃的现象,一个网站能接受的并发量是有限的,通过洪水攻击,十几台机器大量伪造IP地址,就可以搞垮一个网站,所以大企业要建立大规模的集群。
什么是socket
socket又叫套接字,我们的网络通信比如HTTP,FTP,ssh他们都要接收数据和发送数据的过程,我们把这个接收数据的过程和发送数据的过程封装起来就是socket,通常我们用一个Socket表示“打开了一个网络链接”
socket内置的方法
socket.socket:声明socket类型,并创建socket对象
socket.bind((‘127.0.0.1’,80)):绑定端口,必须注意这里是一个元组,IP地址使用字符串的形式写入元组
socket.listen(5):监听端口,可以设置一个最大连接数,最多可以设置多少个连接
server.accept():接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。接收TCP 客户的连接(阻塞式)等待连接的到来,这个函数用来表示一个等待的状态
server.close:关闭套接字
sc.recv(bufsize[,flag]):
接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的多少字节。flag提供有关消息的其他信息,通常可以忽略。
sc.send(string[,flag]):
将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。
sc.sendall() :就是简单的循环send
socket.gethostname():获取本地主机名
一个简单的socket案例
服务端代码:
#!/usr/local/bin/python3
#coding:utf-8
"""思路:
1.服务端先import socket
2.创建socket并连接
2.进行端口的绑定,使用bind,传一个元组进去
4.监听端口
5.等待连接
6.接收到数据
7.发送数据
"""
import socket
server = socket.socket() # 声明socket类型,同时生成socket连接对象
server.bind(('127.0.0.1', 9999)) # 绑定端口
server.listen(5) #
# 监听端口,参数可以设置最多连接数,也就是最多可以挂起多少个连接
print('我要开始等电话了')
conn, addr = server.accept()
# server.accept()会返回两个值,一个是标志位,一个是地址位
# cron是客户端连过来而在服务端为其生成的一个实例
print("电话来了")
# 听电话
data = conn.recv(1024) # recv的大小是有限制的,不能一次性都接收过来
print("recv:", data)
conn.send(data.upper()) # send的时候不能send为空,不然就会一直卡在这里
server.close()
客户端代码
#!/usr/local/bin/python3
#coding:utf-8
# 实现网络编程,思路是
"""
1.先创建socket连接,
2.发送数据
3。接收数据
"""
import socket
client = socket.socket() # 创建socket类型,同时生成socket连接对象
client.connect(('127.0.0.1', 9999)) # 连接这里必须是一个元组
client.send(b"hello")
# 以bytes类型发送,Python3不能直接发字符串,Python2都可以
data = client.recv(1024)
# 设置接收1k的数据,在centos里面设置很大都不会报错,但是Ubuntu会
print(data)
client.close()
改进上面的代码,实现一直在互相通信
客户端
import socket
client = socket.socket() #声明socket类型,同时生成socket连接对象
client.connect(('localhost',6969))
while True:
msg = input(">>:").strip()
if len(msg) == 0:continue
client.send(msg.encode("utf-8"))
data = client.recv(10240)
print("recv:",data.decode())
client.close()
服务端
import socket
client = socket.socket() #声明socket类型,同时生成socket连接对象
client.connect(('localhost',6969))
while True:
msg = input(">>:").strip()
if len(msg) == 0:continue
client.send(msg.encode("utf-8"))
data = client.recv(10240)
print("recv:",data.decode())
client.close()
这个好像没啥意思,但是依赖这些基础可以做个ssh工具或者FTP。
socket粘包的概念
1.“粘包”, 即服务器端你调用时send 2次,但你send调用时,数据其实并没有立刻被发送给客户端,而是放到了系统的socket发送缓冲区
里,等缓冲区满
了、或者数据等待超时
了,数据才会被send到客户端,这样就把好几次的小数据拼成一个大数据
,统一发送到客户端了,这么做的目地是为了提高io利用效率
,一次性发送总比连发好几次效率高嘛。 但也带来一个问题,就是“粘包”,即2次或多次的数据粘在了一起统一发送了。
2. 解决粘包的问题:我们可以在两次send之间加上一个recv()来接收确认信息,然后在另一方发送确认信息,conn.recv()会一直等待客户端发个确认信息过来,这样避免粘包,我们也可以让程序sleep(0.5)秒来避免,但是会降低程序性能,这是一种比较笨的方法。
socketserver(进阶)
socketserver是socket的再封装,socket无法支持多用户,而socketserver支持多用户多并发。
使用socketserver的步骤:
- 首先必须自己创建一个请求处理类,这个类要继承自BaseRequestHandle,然后重写父类的handle方法。
- 实例化TCPServer,然后传递server_ip和我们创建的请求处理类作为参数给TCPServer
- 调用
server.handle_request()
:只能处理一次
调用server.serve_forever()
可以处理多次。 - Finally, call
server_close()
to close the socket.
注意
- handle()函数里面处理与客户端的交互
- 在handle里面加循环,不然连一个就会断了
- 在python3里面,这段代码会抛异常,要注意捕捉异常
开发的过程遇到的坑以及心得
初学网络编程,边学边做,遇到开发的一些巨坑。
- 开发FTP服务器时,开发切换目录这个功能,不能调用os.system('cd '),这是个大坑,因为os.system每一次调用的时候都会开启一个新的终端来执行命令,当执行完命令,就会把这个终端咔嚓关掉,所以最终目录还是没有切换。所以要使用os.chdir()来切换,但是这个也不太好使,它好使是因为当前用户确实切换目录了,但是你切换的是sockerserver的工作目录,也就是说服务器端的目录根本就没有切换,只是客户端切换了,并且客户端自己ls一下,也发现确实有那个目录下面的东西
- 使用socketServer的时候要注意想实现多线程必须调用ThreadingTCPServer,调TCPServer还是不能实现多线程的
- ForkingTCPServer虽然在Linux上可以实现和ThreadingTCPServer一样的效果,但是在Windows上不行,因为两个系统的进程管理方式不一样。
- ThreadingTCPServer每来一个请求,就会开启一个新的进程来处理请求
- json的使用,写FTP的时候用过一下,在网络编程里面有时候我们想给接收方发送一个字典,那么可以先把它转化为json格式,然后在encode一下,转成bytes类型,然后接收方接收时先decode一下,在把这个json字符串使用loads方法转为Python的数据类型
- 在写FTP的时候还用到了刚刚学到的语法:反射(通过字符串去映射到类里面的属性),很nice
待更新