Python学习
网络编程
1. C/S架构
C: Client、S: Server,即客户机和服务器结构。Server唯一的目的就是等待Client的请求,Client连上Server发送必要的数据,然后等待Server端完成请求的反馈。
基本原理:Server端进行设置,首先创建一个通信端点,让Server端能够监听请求,之后就进入等待和处理Client请求的无限循环中。Client编程相对Server端编程简单,只要创建一个通信端点,建立到服务器的连接,就可以提出请求了。
2. Python提供的网络服务
Python 提供了两个级别访问的网络服务。
- 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的全部方法。
- 高级别的网络服务模块 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发。
- 什么是 Socket?
Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。
3. socket()函数
socket.socket(family, type)
- family: 套接字家族可以是 AF_UNIX 或者 AF_INET;
AF_UNIX 和 AF_INET是两种不同的通信域,AF_UNIX域只能用于本机内进程通信、AF_INET不仅可以用作本机的跨进程通信,同样的可以用于不同机器之间的通信。
AF_INET需经过多个协议层的编解码,消耗系统cpu,并且数据传输需要经过网卡,受到网卡带宽的限制。AF_UNIX数据到达内核缓冲区后,由内核根据指定路径名找到接收方socket对应的内核缓冲区,直接将数据拷贝过去,不经过协议层编解码,节省系统cpu,并且不经过网卡,因此不受网卡带宽的限制。所以AF_UNIX的传输速率远远大于AF_INET。
- type:套接字类型可以根据是面向连接的还是非连接分为:SOCK_STREAM或SOCK_DGRAM
如:创建TCP/IP套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- 服务端套接字的方法
s.bind()
# 绑定地址(host,port)到套接字,以元组(host,port)的形式表示地址。
s.listen()
# 开始TCP监听,操作系统可以挂起的最大连接数量,该值至少为1,大部分应用程序设为5就可以了。
s.accept()
# 被动接受TCP客户端连接,(阻塞式)等待连接的到来
- 客户端套接字方法
s.connect()
# 主动初始化TCP服务器连接,一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
s.connect_ex()
# connect函数的扩展版本,出错时返回错误代码,而不抛出异常
s.recv()
# 接收TCP数据,数据以字符串形式返回,要指定接收的最大数据量
- 公共用途套接字方法
s.recv() 接受TCP数据
s.send() 发送TCP数据
s.sendall() 完整发送TCP数据
s.recvfrom() 接受UDP数据
s.sendto() 发送UDP数据
s.getpeemame() 连接到当前套接字的远端地址
s.getsockname() 当前套接字的地址
s.getsockopt( 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字
4. 实例
4.1 实例一
基于C/S架构创建一个TCP服务端和客户端。
- 服务端:
import socket
# 创建 socket 对象
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 获取本地主机名
host = socket.gethostname()
port = 8888
# 绑定端口号
serversocket.bind((host, port))
# 设置最大连接数,超过后排队
serversocket.listen(5)
while True:
# 建立客户端连接
clientsocket,addr = serversocket.accept()
print("连接地址: %s" % str(addr))
msg='欢迎访问服务端!'+ "\r\n"
clientsocket.send(msg.encode('utf-8'))
clientsocket.close()
- 客户端
import socket
# 创建 socket 对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 获取本地主机名
host = socket.gethostname()
# 设置端口号
port = 8888
# 连接服务,指定主机和端口
s.connect((host, port))
# 接收小于 1024 字节的数据
msg = s.recv(1024)
s.close()
print (msg.decode('utf-8'))
先运行服务端,然后运行客户端,结果:
4.1 实例二
基于C/S架构创建一个TCP服务端和客户端,并实现通信和cmd命令。
- 服务端
import socket
import time
import os
COD = 'utf-8'
HOST = socket.gethostname()
PORT = 9999
BUFSIZ = 1024
SIZE = 5
ADDR = (HOST, PORT)
tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建套接字
tcpServer.bind(ADDR) # 绑定ip端口号
tcpServer.listen(SIZE) # 设置最大链接数
while True:
print("服务器启动,监听客户端连接...")
tcpClient, addr = tcpServer.accept()
print("连接的客户端为:", addr)
while True:
try:
data = tcpClient.recv(BUFSIZ).decode(COD)
x = time.strftime("%Y-%m-%d %X")
msg = '[%s ==> Client]:%s' % (x, data)
if data == 'cmd':
print(msg)
tcpClient.send('已进入命令行模式...'.encode(COD))
while True:
data = tcpClient.recv(BUFSIZ).decode(COD)
tcpClient.send(os.popen(data).read().encode(COD))
else:
print(msg)
data = input('Server~:')
tcpClient.send(data.encode('utf-8'))
except Exception:
print("断开的客户端为:", addr)
break
# 关闭连接
tcpClient.close()
tcpServer.close()
- 客户端
import socket
import time
HOST = socket.gethostname()
PORT = 9999
BUFSIZ = 1024
COD = 'utf-8'
ADDR = (HOST, PORT)
tcpClient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpClient.connect(ADDR)
while True:
msg = input('Client~:')
x = time.strftime("%Y-%m-%d %X")
tcpClient.send(msg.encode(COD))
recv_data = tcpClient.recv(1024).decode(COD)
result = '[%s ==> Server]:%s' % (x, recv_data)
print(result)
# 关闭连接
tcpClient.close()
运行结果:
客户端
服务端
5. 端口扫描
原理:使用 s.connect(hostname,port) 方法进行TCP服务器连接,连接成功即该端口开放,反之关闭。
import socket
print('Please input ip:')
ip = input()
print('Please input ports(use , separated):')
ports = input().split(',') # 用列表存储
def do_open(ip, ports):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((ip, ports))
return True
except:
return False
def do_scanPort(ip, ports):
print('Start port scan...')
for i in ports:
if do_open(ip, int(i)):
print('%s ==> host %s is [open]' % (ip, i))
else:
print('%s ==> host %s is [close]' % (ip, i))
if __name__ == '__main__':
do_scanPort(ip, ports)
扫描结果:
6. 网络编程的其他模块
协议 功能 端口号 Python模块
HTTP 网页访问 80 httplib, urllib, xmlrpclib
NNTP 阅读和张贴新闻文章 119 nntplib
FTP 文件传输 20 ftplib, urllib
SMTP 发送邮件 25 smtplib
POP3 接收邮件 110 poplib
IMAP4 获取邮件 143 imaplib
Telnet 命令行 23 telnetlib
Gopher 信息查找 70 gopherlib, urllib