首先了解socket工作原理,client-server模式
1、socket客户端:
2、socket类型
3、socket数据流
4、实验
(1)写一个client
服务端启动监听ip和端口
admindeMacBook-Air-62:~ admin$ nc -l 1234
客户端连接服务端,发数据,关闭socket
pycharm中添加一个socket_client.py并之行:
import socket
HOST = '127.0.0.1'
PORT = 1234
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST,PORT))
s.sendall('hello world')
s.close()
服务端退出socket
admindeMacBook-Air-62:~ admin$ nc -l 1234
hello world
admindeMacBook-Air-62:~ admin$
客户端发送10次
socket_client10.py
#-*-coding: UTF-8 -*-
#coding=utf-8
import socket
import time
HOST = '127.0.0.1'
PORT = 1234
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #元祖(网络socket,tcp)
s.connect((HOST,PORT))
for i in range(10):
s.sendall('%s hello, world\n' %i)
time.sleep(1)
s.close()
服务端打印10次退出
admindeMacBook-Air-62:~ admin$ nc -l 1234
0 hello, world
1 hello, world
2 hello, world
3 hello, world
4 hello, world
5 hello, world
6 hello, world
7 hello, world
8 hello, world
9 hello, world
admindeMacBook-Air-62:~ admin$
(2)写一个server
socket_server01.py
#coding=UTF-8
import socket
import time
HOST = '' #表示监听0.0.0.0
PORT = 1234
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #网络,tcp
s.bind((HOST,PORT))
s.listen(1) #一次接受一个,写2也是一次接受一个
connect, address = s.accept() #接受客户端的请求,返回的是一个连结句柄connect+地址
print 'connent',connect
print 'Connected by', address
while 1:
data = connect.recv(1024)
if not data: break
connect.sendall(data.upper())
connect.close()
admindeMacBook-Air-62:host_performance-monitor admin$ python socket_server01.py
启动程序并查看端口
admindeMacBook-Air-62:~ admin$ netstat -an | grep 1234
tcp4 0 0 *.1234 *.* LISTEN
客户端:
socket-client for server.py
#-*-coding: UTF-8 -*-
#coding=utf-8
import socket
import time
HOST = '127.0.0.1'
PORT = 1234
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #网络socket,tcp
s.connect((HOST,PORT))
s.sendall('hello, world') #客户端发送1024字节
data = s.recv(1024) #接受服务器发送过来的数据
s.close()
print 'Received', repr(data) #打印服务端发送过来的数据
print data
客户端之行发送hello world,接受HELLO WORLD
python socket-client for server.py
Received 'HELLO, WORLD'
HELLO, WORLD
admindeMacBook-Air-62:host_performance-monitor admin$ python socket_server01.py
connent <socket._socketobject object at 0x10427ec20>
Connected by ('127.0.0.1', 63878)
现在让客户端一直发,服务端一直接受数据,一端关闭socket连接,另一端也自动关闭连接
server端代码基本上不变
socket_server01.py
#coding=UTF-8
import socket
import time
HOST = '' #表示监听0.0.0.0
PORT = 1234
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #网络,tcp
s.bind((HOST,PORT))
s.listen(1) #一次接受一个,写2也是一次接受一个
connect, address = s.accept() #接受客户端的请求,返回的是一个连结句柄connect+地址
print 'connent',connect
print 'Connected by', address
while 1:
data = connect.recv(1024)
print data
if not data: break
connect.sendall(data.upper())
connect.close()
启动server,并查看端口:
admindeMacBook-Air-62:host_performance-monitor admin$ python socket_server01.py
admindeMacBook-Air-62:~ admin$ netstat -an | grep 1234
tcp4 0 0 *.1234 *.* LISTEN
client端代码:
vim clinet_not_stop.py
#-*-coding: UTF-8 -*-
#coding=utf-8
import socket
import time
HOST = '127.0.0.1'
PORT = 1234
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #网络socket,tcp
s.connect((HOST,PORT))
while True:
s.sendall('hello, world') #客户端发送1024字节
data = s.recv(1024) #接受服务器发送过来的数据
print data
time.sleep(1)
s.close()
admindeMacBook-Air-62:host_performance-monitor admin$ python python clinet_not_stop.py client接受到server大写返回
HELLO, WORLD
HELLO, WORLD
HELLO, WORLD
HELLO, WORLD
HELLO, WORLD
HELLO, WORLD
HELLO, WORLD
HELLO, WORLD
同时可以看到server端的来自client的发送数据,全部小写的hello world
admindeMacBook-Air-62:host_performance-monitor admin$ python socket_server01.py
connent <socket._socketobject object at 0x10baedc20>
Connected by ('127.0.0.1', 64589)
hello, world
hello, world
hello, world
hello, world
hello, world
hello, world
hello, world
hello, world
按ctrl+c终止传输
新的需求,客户端发送命令,服务端接收命令并之行,并返回结果,客户端使用exit或者quit,退出。
server:socket_server_command.py
#-*-coding: UTF-8 -*-
#coding=UTF-8
import socket
from subprocess import Popen,PIPE
HOST = '' #表示监听0.0.0.0
PORT = 1234
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #网络,tcp
s.bind((HOST,PORT))
s.listen(1) #一次接受一个,写2也是一次接受一个
connect, address = s.accept() #接受客户端的请求,返回的是一个连结句柄connect+地址
print 'connent',connect
print 'Connected by', address
while 1:
cmd = connect.recv(1024)
p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
stdout = p.stdout.read()
stderr = p.stderr.read()
if stdout:
connect.sendall(stdout)
if stderr:
connect.sendall(stderr)
if not cmd: break
connect.close()
client:socket_clinet_command.py
#-*-coding: UTF-8 -*-
#coding=utf-8
import socket
import time
import tab #参考:http://daixuan.blog.51cto.com/5426657/1934112
HOST = '127.0.0.1'
PORT = 1234
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #网络socket,tcp
s.connect((HOST,PORT))
while True:
cmd = raw_input("Please input cmd:").strip() #把空字符串命令去掉,做一个判断,非空再发送
if cmd.lower() == 'exit' or cmd.lower() == 'quit':
break
if cmd:
s.sendall(cmd) #客户端发送命令
data = s.recv(1024) #接受服务器发送过来的数据
print data
s.close()
server启动服务:(有客户端连接会显示连接句柄)
admindeMacBook-Air-62:host_performance-monitor admin$ python socket_server_command.py
connent <socket._socketobject object at 0x109192de0>
Connected by ('127.0.0.1', 65512)
客户端启动并之行命令:
admindeMacBook-Air-62:host_performance-monitor admin$ python socket_clinet_command.py
Please input cmd:date
2017年 6月10日 星期六 18时34分21秒 CST
Please input cmd:pwd
/Users/admin/Desktop/project/host_performance-monitor
Please input cmd:exit
5、实现FTP下载功能:
1、get source dest
2、重复文件,加.new
3、打印出来get下来的文件名是/tmp/hosts 还是/tmp/hosts.new
服务端:socket_server_ftp.py
#-*-coding: UTF-8 -*-
#coding=UTF-8
import socket
from subprocess import Popen,PIPE
HOST = '' #表示监听0.0.0.0
PORT = 1234
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #网络,tcp
s.bind((HOST,PORT))
s.listen(1) #一次接受一个,写2也是一次接受一个
connect, address = s.accept() #接受客户端的请求,返回的是一个连结句柄connect+地址
print 'connent',connect
print 'Connected by', address
while 1:
cmd = connect.recv(1024)
cmd_list = cmd.split()
if cmd_list[0] == 'get': #如果是get方法,读数据
with open(cmd_list[1]) as fd:
while True: #循环读取1024字节,然后返回一个数
data = fd.read(1024)
connect.sendall(data)
if not data: #数据读完了,跳出while循环
connect.sendall('EOF')
break
if not cmd: break
connect.close()
客户端:socket_clinet_ftp.py
#-*-coding: UTF-8 -*-
#coding=utf-8
import socket
import time
import tab #参考:http://daixuan.blog.51cto.com/5426657/1934112
import os
HOST = '127.0.0.1'
PORT = 1234
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #网络socket,tcp
s.connect((HOST,PORT))
while True:
cmd = raw_input("Please input cmd:").strip() #把空字符串命令去掉,做一个判断,非空再发送
if cmd.lower() == 'exit' or cmd.lower() == 'quit':
break
cmd_list = cmd.split()
if len(cmd_list) != 3:
print "Ex: get file1 file2"
continue
else:
s.sendall(cmd) #客户端发送命令
if not os.path.exists(cmd_list[2]):
dst_file = cmd_list[2]
else:
dst_file = cmd_list[2]+'.new'
n = 1 #定义一个变量,第一次打开文件是wb方式,第二次打开文件是a(追加)的方式打开。
while True:
data_rev = s.recv(1024) # 接受服务器发送过来的数据,但是服务器发送完数据,客户端仍在等待,就会卡住。用EOF,就break
if data_rev.endswith('EOF'):
data = data_rev[:-3]
else:
data = data_rev
if n == 1:
with open(dst_file, 'wb') as fd:
fd.write(data)
else:
with open(dst_file, 'a') as fd:
fd.write(data)
print data
n +=1
print "destination file is %s" %dst_file
if data_rev[-3:] == 'EOF': #如果最后三个字符是EOF,退出ftp
break
s.close()
启动服务端:
admindeMacBook-Air-62:host_performance-monitor admin$ python socket_server_ftp.py
connent <socket._socketobject object at 0x104ecbde0>
Connected by ('127.0.0.1', 53858)
启动客户端:
admindeMacBook-Air-62:host_performance-monitor admin$ python socket_clinet_ftp.py
Please input cmd:get /etc/hosts /tmp/hosts
destination file is /tmp/hosts
Please input cmd:get /etc/hosts /tmp/hosts
destination file is /tmp/hosts.new
6、SocketServer
socketserver是一个类,自带多线程
编写一个hander类,继承BaseRequestHander,重写handle()方法
针对tcp还是udp生成一个server对象
调用server对象的handle_request或者sever_forver方法
(1)socket server官方的例子,一个脚本中服务端核客户端
https://docs.python.org/2.7/library/socketserver.html?highlight=socketserver
vim socket-threading-thread.py
import socket
import threading
import SocketServer
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)
cur_thread = threading.current_thread()
response = "%s %s" % (cur_thread.name, data)
self.request.sendall(response)
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
def client(ip, port, message):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, port))
try:
sock.sendall(message)
response = sock.recv(1024)
print response
finally:
sock.close()
if __name__ == "__main__":
# Port 0 means to select an arbitrary unused port
HOST, PORT = "localhost", 0
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
print "Server loop running in thread:", server_thread.name
client(ip, port, "Hello World 1")
client(ip, port, "Hello World 2")
client(ip, port, "Hello World 3")
server.shutdown()
server.server_close()
admindeMacBook-Air-62:host_performance-monitor admin$ python socket-threading-thread.py
Server loop running in thread: Thread-1
Thread-2 Hello World 1
Thread-3 Hello World 2
Thread-4 Hello World 3
(2)多个客户端同时连接一个服务器
服务器不退出
任何一个客户端都会有返回的结果
服务端代码:
vim socket_clinet_command.py
#-*-coding: UTF-8 -*-
#coding=UTF-8
import socket
import threading
import SocketServer
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
while True:
self.data = self.request.recv(1024).strip()
print self.client_address[0]
print self.data
self.request.sendall(self.data.upper())
if not self.data:
break
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
if __name__ == "__main__":
# Port 0 means to select an arbitrary unused port
#HOST, PORT = "localhost", 9999
HOST = 'localhost'
PORT = 9999
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
print "Server loop running in thread:", server_thread.name
##主要进程不退出
server.serve_forever()
客户端代码:
socketserver_clinet.py
#-*-coding: UTF-8 -*-
#coding=utf-8
import socket
import time
import tab #参考:http://daixuan.blog.51cto.com/5426657/1934112
import os
HOST = 'localhost'
PORT = 9999
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((HOST,PORT))
while True:
s.sendall('hello, world')
data = s.recv(1024)
print data
time.sleep(1)
s.close()
启动服务端
Server loop running in thread: Thread-1
127.0.0.1
hello, world
127.0.0.1
hello, world
127.0.0.1
hello, world
127.0.0.1
hello, world
分别启动两个客户端:
返回结果都是大写helloworld,且相互不影响。
HELLO, WORLD HELLO, WORLD HELLO, WORLD HELLO, WORLD HELLO, WORLD HELLO, WORLD HELLO, WORLD HELLO, WORLD
(3)使用socketserver的threading多线程实现ftp功能(多客户端)
服务器端代码:
#-*-coding: UTF-8 -*-
#coding=UTF-8
import socket
import threading
import SocketServer
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
while True:
self.cmd = self.request.recv(1024).strip()
self.cmd_list = self.cmd.split()
if self.cmd_list[0] == 'get': # 如果是get方法,读数据
with open(self.cmd_list[1]) as fd:
while True: # 循环读取1024字节,然后返回一个数
self.data = fd.read(1024)
self.request.sendall(self.data)
if not self.data: # 数据读完了,跳出while循环
self.request.sendall('EOF')
break
if not self.cmd:
break
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
if __name__ == "__main__":
# Port 0 means to select an arbitrary unused port
#HOST, PORT = "localhost", 9999
HOST = ''
PORT = 12345
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
print "Server loop running in thread:", server_thread.name
##主要进程不退出
server.serve_forever()
启动服务端监听端口:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /Users/admin/Desktop/project/host_performance-monitor/socket-threading-thread-server-ftp.py
Server loop running in thread: Thread-1
客户端代码:
socket_clinet_ftp.py
#-*-coding: UTF-8 -*-
#coding=utf-8
import socket
import time
import tab #参考:http://daixuan.blog.51cto.com/5426657/1934112
import os
HOST = '127.0.0.1'
PORT = 12345
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #网络socket,tcp
s.connect((HOST,PORT))
while True:
cmd = raw_input("Please input cmd:").strip() #把空字符串命令去掉,做一个判断,非空再发送
if cmd.lower() == 'exit' or cmd.lower() == 'quit':
break
cmd_list = cmd.split()
if len(cmd_list) != 3:
print "Ex: get file1 file2"
continue
else:
s.sendall(cmd) #客户端发送命令
if not os.path.exists(cmd_list[2]):
dst_file = cmd_list[2]
else:
dst_file = cmd_list[2]+'.new'
n = 1 #定义一个变量,第一次打开文件是wb方式,第二次打开文件是a(追加)的方式打开。
while True:
data_rev = s.recv(1024) # 接受服务器发送过来的数据,但是服务器发送完数据,客户端仍在等待,就会卡住。用EOF,就break
if data_rev.endswith('EOF'):
data = data_rev[:-3]
else:
data = data_rev
if n == 1:
with open(dst_file, 'wb') as fd:
fd.write(data)
else:
with open(dst_file, 'a') as fd:
fd.write(data)
print data
n +=1
print "destination file is %s" %dst_file
if data_rev[-3:] == 'EOF': #如果最后三个字符是EOF,退出ftp
break
s.close()
分别启动两个客户端,可以同时使用get方法,断开其中一个客户端对服务端无影响。
客户端1:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /Users/admin/Desktop/project/host_performance-monitor/socket_clinet_ftp.py
Please input cmd:ls
Ex: get file1 file2
Please input cmd:get /tmp/1.txt /tmp/2.txt
destination file is /tmp/2.txt
Please input cmd:
客户端2:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /Users/admin/Desktop/project/host_performance-monitor/socket_clinet_ftp.py
Please input cmd:get /tmp/1.txt /tmp/2.txt
destination file is /tmp/2.txt.new
destination file is /tmp/2.txt.new
Please input cmd:
Ex: get file1 file2
Please input cmd:get /tmp/1.txt /tmp/2.txt
destination file is /tmp/2.txt.new
destination file is /tmp/2.txt.new
Please input cmd:
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。