1、socket
- 如何通信
- 同一台主机上,通过端口号就可以唯一标识一个进程
- 在网络中,ip+协议+端口号可以表示网络中的一个进程
- socket使用
- socket(套接字):进程通信的一种方式,它能实现不同主机间的进程通信,我们网络上各种各样的服务大部分都是通过socket实现的
- API(具体使用见例子)
SOCKET = socket.socket()
创建一个套接字SOCKET.sendto()
发送数据SOCKET.bind()
绑定ip和portSOCKET.recvfrom()
返回接收到的数据SOCKET.close()
关闭套接字
- socket的机制
- socket是全双工,一个socket可以发也可以收
- 端口通信的机制(以python实现socket为例):
- 当我们创建一个套接字并在等待接受数据,在未接收到数据前,进程是阻塞的
- 如果其它的机器给我们的某一个端口发信息,如果我们用套接字接受数据,那么就会收到数据
- 但是如果我们没有使用socket.recvfrom()接受数据,操作系统会把收到的信息存起来,等待接受
- 拒绝服务攻击:扫描一台机器的端口,查到哪个端口是开着的,就不停地向该端口发送数据,知道容量被占满
2、tcp
- tcp介绍
- TCP协议(Transmission Control Protocol):一种面向连接的、可靠的、基于字节流的传输层通信协议
- UDP协议(User Datagram Protocol):一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务
- TCP、UDP区别:
- udp通信模型中,在通信开始之前,不需要建立相关的连接,只发送数据(不安全)
- tcp通信需要经过“创建连接”、“数据传送”和“终止连接”,在通信开始之前,要建立相关连接(安全)
- python编程实现tcp通信
- tcp严格区分服务端和客户端
- 客户端流程
- 创建套接字:
socket.socket()
- 连接服务器:
socket.connect()
- 传送数据/接受数据:
socket.send()
socket.recv()
- 服务端创建一个套接字并监听这个套接字,当有客户端连接服务器时,服务器获得客户端的地址,并分配一个新套接字用于与这个客户端通信
- 创建套接字:
socket.socket()
- 绑定端口:
socket.bind()
- 监听端口(将主动套接字变为被动套接字):
socket.listen(128)
- 等待连接(返回客服端地址和一个新套接字):
socket.accept()
- 接受/发送:
socket.recv()
socket.send()
- 关于程序阻塞
- 当客户端连接上服务器,服务器在等待客户端发送数据时,程序阻塞
- 只有以下两种情况,程序解阻塞:
3、例子
(1)使用UDP通信
import socket
def main():
udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udpSocket.bind(("", 3000))
ip = "127.0.0.1"
port = "2000"
udpSocket.sendto(("hello, I am %s:%s" % (ip, port)).encode("utf-8"), (ip, int(port)))
udpSocket.close()
if __name__ == "__main__":
main()
import socket
def main():
udpSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udpSocket.bind(("", 2000))
data = udpSocket.recvfrom(1024)
print("ip:%s-port:%s接受到:%s" % (data[1][0], data[1][1], data[0].decode("utf-8")))
udpSocket.close()
if __name__ == "__main__":
print("------run------")
main()
print("------end------")
dream:Web相关 dream$ python socket_udp_accept.py
dream:Web相关 dream$ python socket_udp_send.py
------run------
ip:127.0.0.1-port:3000接受到:hello, I am 127.0.0.1:2000
------end------
(2)使用tcp通信
import socket
def main():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("", 10000))
server_socket.listen(128)
print("------------等待中-----------")
new_socket, client_addr = server_socket.accept()
data = new_socket.recv(1024).decode("utf-8")
print(client_addr, "发送数据:", data)
message = b"Hello, Client!"
print("回复:" + message.decode("utf-8"))
new_socket.send(message)
print("已关闭客户端套接字")
new_socket.close()
print("-----------关闭服务器--------")
server_socket.close()
if __name__ == "__main__":
main()
import socket
def main():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("", 10000))
print("---------已连接上服务器--------")
message = b"Hello, Server!"
print("发送:" + message.decode("utf-8"))
client_socket.send(message)
data = client_socket.recv(1024)
print("接收:" + data.decode("utf-8"))
print("------------连接断开----------")
client_socket.close()
if __name__ == "__main__":
main()
dream:Web相关 dream$ python socket_tcp_server.py
------------等待中-----------
dream:Web相关 dream$ python socket_tcp_clinet.py
---------已连接上服务器--------
发送:Hello, Server!
接收:Hello, Client!
------------连接断开----------
dream:Web相关 dream$ python socket_tcp_server.py
------------等待中-----------
('127.0.0.1', 61979) 发送数据: Hello, Server!
回复:Hello, Client!
已关闭客户端套接字
-----------关闭服务器--------
4、使用socket实现简单的ssh
import socket
import subprocess
import struct
def main():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("", 11111))
server_socket.listen(5)
while True:
client_socket, client_addr = server_socket.accept()
print(client_addr, "已连接到本机")
while True:
try:
data = client_socket.recv(1024).decode("utf-8")
if data == "exit":
client_socket.close()
print("客户端已退出")
break
ret = subprocess.Popen(data, shell=True,
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
out = ret.stdout.read()
err = ret.stderr.read()
if bool(out):
out_len = struct.pack('i', len(out))
client_socket.send(out_len)
client_socket.send(out)
else:
err_len = struct.pack('i', len(err))
client_socket.send(err_len)
client_socket.send(err)
except Exception:
client_socket.close()
print('客户端异常退出,已关闭连接')
break
main()
import socket
import struct
def main():
flag = 'Y'
while flag == 'Y' or flag == 'y':
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_IP = input("请输入服务器IPv4地址:")
server_info = (server_IP, 11111)
client_socket.connect(server_info)
print('已连接到服务器')
while True:
cmd = input("请输入命令:")
client_socket.send(cmd.encode('utf-8'))
if cmd == 'exit':
client_socket.close()
print("已退出")
break
else:
data_len_packed = client_socket.recv(4)
data_len = struct.unpack('i', data_len_packed)[0]
length = 0
info = b''
while length < data_len:
data = client_socket.recv(1024)
info = info + data
length += len(data)
print('返回信息长度为: ', length)
print(info.decode('utf-8'))
flag = input("请问是否继续(若继续请输入Y/y):")
main()
dream:sshTest dream$ python ssh_server.py
('127.0.0.1', 62012) 已连接到本机
客户端已退出
('127.0.0.1', 62014) 已连接到本机
客户端已退出
dream:sshTest dream$ python ssh_client.py
请输入服务器IPv4地址:127.0.0.1
已连接到服务器
请输入命令:pwd
返回信息长度为: 48
/Users/dream/Desktop/Source/python/test/sshTest
请输入命令:ls
返回信息长度为: 28
ssh_client.py
ssh_server.py
请输入命令:ifconfig
返回信息长度为: 3081
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201<PERFORMNUD,DAD>
...(后面的内容略)
请输入命令:exit
已退出
请问是否继续(若继续请输入Y/y):Y
请输入服务器IPv4地址:127.0.0.1
已连接到服务器
请输入命令:pwd
返回信息长度为: 48
/Users/dream/Desktop/Source/python/test/sshTest
请输入命令:exit
已退出
请问是否继续(若继续请输入Y/y):n