Socket:套接字。作用:我们只需要安照socket的规定去编程,就不需要深入理解tcp/udp协议也可以实现

1:TCP协议

1.1  客户端服务端循环收发消息

# 1:引入stock模块(导包)
import socket
#2:创建服务端对象
tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#3:绑定接口地址和端口号
ip_port=("127.0.0.1",8000)
back_log=5
buffer_size=1024
tcp_server.bind(ip_port)
#4: 开启监听(设置监听数量)
tcp_server.listen(back_log)
print("服务端开始运行了")
# 5:准备接收消息
conn, add = tcp_server.accept()
while True:
#6:接收消息
data=conn.recv(buffer_size)
print("客户端发送的消息是:",data.decode("utf-8"))
#7:发送消息
conn.send(data.upper())
# 8:关闭连接
conn.close()
# 9:关闭服务端对象
tcp_server.close()

服务端

#1:引入模块
from socket import *
#2:创建对象
tcp_client = socket(AF_INET,SOCK_STREAM)
#3:建立连接
ip_port=("127.0.0.1",8000)
buffer_size=1024
tcp_client.connect(ip_port)
while True:
msg=input("请输入待发送的消息:")
#4:发消息
tcp_client.send(msg.encode("utf-8"))
# 5:收消息
data=tcp_client.recv(buffer_size)
print("收到服务端传来的消息",data.decode("utf-8"))
tcp_client.close()

客户端

1.2 服务端循环链接请求来收发消息

# 1:引入stock模块(导包)
import socket
#2:创建服务端对象
tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#3:绑定接口地址和端口号
ip_port=("127.0.0.1",8000)
back_log=5
buffer_size=1024
tcp_server.bind(ip_port)
#4: 开启监听(设置监听数量)
tcp_server.listen(back_log)
print("服务端开始运行了")
while True:
# 5:准备接收消息
conn, add = tcp_server.accept()
while True:
# 客户端断开连接的时候会报错
try:
# 6:接收消息
data = conn.recv(buffer_size)
# 据说Linux系统即使客户端断开连接也不会抛异常,这是需要手处理一下
if not data:break
print("客户端发送的消息是:", data.decode("utf-8"))
# 7:发送消息
conn.send(data.upper())
except Exception:
break
# 8:关闭连接
conn.close()
# 9:关闭服务端对象
tcp_server.close()
# 改进方向
# 1:把5和8放入到循环中,这样就可以实现多连接了
# 2:在内部连接中设置break方法

服务端

#1:引入模块
from socket import *
#2:创建对象
tcp_client = socket(AF_INET,SOCK_STREAM)
#3:建立连接
ip_port=("127.0.0.1",8000)
buffer_size=1024
tcp_client.connect_ex(ip_port)
while True:
msg=input("请输入待发送的消息:")
#如果不加这句,当输入换行时,服务器端会阻塞
if len(msg)==0:
continue
#4:发消息
tcp_client.send(msg.encode("utf-8"))
# 5:收消息
data=tcp_client.recv(buffer_size)
print("收到服务端传来的消息",data.decode("utf-8"))
tcp_client.close()

客户端

1.3 从代码层面解决 “通常每个套接字地址(协议/网络地址/端口)只允许使用一次。”问题,在bind前加下一句代码

tcp_server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

2:UDP协议

2.1  客户端服务端循环收发消息

# 1:引入stock模块(导包)
from socket import *
from time import strftime
#2:创建服务端对象
udp_server =socket(AF_INET,SOCK_DGRAM)
#3:绑定接口地址和端口号
ip_port=("127.0.0.1",8000)
back_log=5
buffer_size=1024
udp_server.bind(ip_port)
print("服务端开始运行了")
while True:
while True:
# 客户端断开连接的时候会报错
try:
# 6:接收消息
data ,add= udp_server.recvfrom(buffer_size)
print("客户端发送的消息是:", data.decode("utf-8"))
# 7:发送消息
time_fmt='%Y-%m-%d %X'
data=strftime(time_fmt)
udp_server.sendto(data.encode("utf-8"),add)
except Exception:
break # 9:关闭服务端对象
udp_server.close()
# udp与tcp的不同之处
# 1:不需要连接s.listen() 监听和 s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来
# 2:通过recvfrom()接收数据;sendto()发送数据
# 3:既然没有连接,也就无所谓谁先启动,或者客户端关闭后是否会引发异常等情况

服务端

#1:引入模块
from socket import *
#2:创建对象
udp_client = socket(AF_INET,SOCK_DGRAM)
#3:建立连接
ip_port=("127.0.0.1",8000)
buffer_size=1024
udp_client.connect_ex(ip_port)
while True:
msg=input("按任意键获取时间:")
# 4:发消息
udp_client.sendto(msg.encode("utf-8"), ip_port)
# 5:收消息
data, add = udp_client.recvfrom(buffer_size)
print("收到服务端传来的时间", data) tcp_client.close()

客户端

3:练习

  3.1 远程操作

  需要使用subprocess模块  

from socket import *
import subprocess
ip_port = ("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_server = socket(AF_INET, SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(back_log)
while True:
conn, add = tcp_server.accept()
print(add)
while True:
try:
cmd = conn.recv(buffer_size);
if not cmd:
conn.close()
break
res = subprocess.Popen(cmd.decode("utf-8"), shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
)
err = res.stderr.read()
if err:
cmd_res = err
else:
cmd_res = res.stdout.read()
# 发
conn.send(cmd_res)
except Exception as e:
print(e)
conn.close()
break
conn.close()
top_server.close()

TCP-Server-1.0

from socket import *

ip_port=("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_client = socket(AF_INET, SOCK_STREAM)
tcp_client.connect(ip_port)
while True:
cmd = input(">>: ").strip()
if not cmd:
continue
if cmd == "quit":
break
tcp_client.send(cmd.encode("utf-8"))
cmd_res = tcp_client.recv(buffer_size)
print(cmd_res.decode("gbk"))
tcp_client.close()

TCP-Client-1.0

  会出现粘包现象:1:tcp-ip内部算法优化,会把短时间内几个小的send信息包在一起发送(tcp-ip的send本身没有界限)2:一次发送量大,一次接受不全

from socket import *
import subprocess
ip_port = ("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_server = socket(AF_INET, SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(back_log)
while True:
conn, add = tcp_server.accept()
print(add)
while True:
try:
cmd = conn.recv(buffer_size);
if not cmd:
conn.close()
break
res = subprocess.Popen(cmd.decode("utf-8"), shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
)
err = res.stderr.read()
if err:
cmd_res = err
else:
cmd_res = res.stdout.read()
# 为了解决粘包的问题,可以在发送的时候先把长度发过去
length=str(len(cmd_res)).encode("utf-8")
conn.send(length)
# 如果直接这么发的话,会出现由于tcp优化出现的粘包情况。
client_s = conn.recv(buffer_size);
print("===>",client_s)
if client_s==b"ready":
conn.send(cmd_res)
except Exception as e:
print(e)
conn.close()
break
conn.close()
top_server.close()

TCP-Server-2.0

from socket import *

ip_port=("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_client = socket(AF_INET, SOCK_STREAM)
tcp_client.connect(ip_port)
while True:
cmd = input(">>: ").strip()
if not cmd:
continue
if cmd == "quit":
break
tcp_client.send(cmd.encode("utf-8"))
res_length=tcp_client.recv(buffer_size); #把获取到的长度转化成intleiixng
cmd_res=""
if res_length:
tcp_client.send("ready".encode("utf-8"))
res_length = int(res_length.decode("gbk"))
print(res_length)
# 循环遍历接收
while len(cmd_res)<res_length:
cur_res=tcp_client.recv(buffer_size).decode("gbk")
cmd_res = cmd_res+cur_res
print(cur_res)
tcp_client.close()

TCP-client-2.0

# 通过引入struct模块,编制一个报文长度,实现一次发送
import struct
from socket import *
import subprocess
ip_port = ("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_server = socket(AF_INET, SOCK_STREAM)
tcp_server.bind(ip_port)
tcp_server.listen(back_log)
while True:
conn, add = tcp_server.accept()
print(add)
while True:
try:
cmd = conn.recv(buffer_size);
if not cmd:
conn.close()
break
res = subprocess.Popen(cmd.decode("utf-8"), shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
)
err = res.stderr.read()
if err:
cmd_res = err
else:
cmd_res = res.stdout.read()
# 为了解决粘包的问题,可以在发送的时候先把长度发过去
length=struct.pack("i",len(cmd_res))
conn.send(length)
conn.send(cmd_res)
print(struct.unpack("i",length)[0])
except Exception as e:
print(e)
conn.close()
break
conn.close()
top_server.close()

TCP-Service # 通过引入struct模块,编制一个报文长度,实现一次发送

# 通过引入struct模块,编制一个报文长度,实现一次发送
from socket import *
import struct
ip_port=("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_client = socket(AF_INET, SOCK_STREAM)
tcp_client.connect(ip_port)
while True:
cmd = input(">>: ").strip()
if not cmd:
continue
if cmd == "quit":
break
tcp_client.send(cmd.encode("utf-8")) #把获取到的长度转化成intleiixng
cmd_res=b''
res_length = tcp_client.recv(4)
length=struct.unpack("i",res_length)[0]
# 循环遍历接收
while len(cmd_res) < length:
cur_res = tcp_client.recv(buffer_size)
cmd_res = cmd_res + cur_res
print(cmd_res.decode("gbk"))
tcp_client.close()

TCP-client-# 通过引入struct模块,编制一个报文长度,实现一次发送

# 通过引入struct模块,实现一次发送
# 通过socketServer实现并发
import struct
from socket import *
import subprocess
import socketserver ip_port = ("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024 # 定义一个实例化的类,主要用于收发消息
class My_server(socketserver.BaseRequestHandler):
def handle(self):
try:
while True:
# 收消息
cmd = self.request.recv(buffer_size)
if not cmd: break
res = subprocess.Popen(cmd.decode("utf-8"), shell=True,
stderr=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
err = res.stderr.read()
if err:
cmd_res = err
else:
cmd_res = res.stdout.read()
# 为了解决粘包的问题,可以在发送的时候先把长度发过去
length = struct.pack("i", len(cmd_res))
self.request.send(length)
self.request.sendall(cmd_res)
except Exception as e:
print(e) #通过线程创建对象
if __name__=="__main__":
s=socketserver.ThreadingTCPServer(ip_port,My_server)
s.serve_forever()

TCP-Service-4.0 通过socketServer实现并发

# 通过引入struct模块,编制一个报文长度,实现一次发送
from socket import *
import struct
ip_port=("127.0.0.1", 8089)
back_log = 5
buffer_size = 1024
tcp_client = socket(AF_INET, SOCK_STREAM)
tcp_client.connect(ip_port)
while True:
cmd = input(">>: ").strip()
if not cmd:
continue
if cmd == "quit":
break
tcp_client.send(cmd.encode("utf-8")) #把获取到的长度转化成intleiixng
cmd_res=b''
res_length = tcp_client.recv(4)
length=struct.unpack("i",res_length)[0]
# 循环遍历接收
while len(cmd_res) < length:
cur_res = tcp_client.recv(buffer_size)
cmd_res = cmd_res + cur_res
print(cmd_res.decode("gbk"))
tcp_client.close()

TCP-client-4.0 通过socketServer实现并发

4:FTP文件上传与下载

  4.1实现客户端与服务端的调通

  首先,创建两个文件夹FTP_server和FTP_client用于存放服务端和客户端的文件

  4.1.1 FTP_server

  创建一个bin文件,里面包含启动文件ftp_server.py

  4.1.1.1 bin文件  

# 主要用于启动
import os,sys
# 此时的路径是当前执行文件的路径,相当于当前的bin目录下寻找core中的main方法
PATH=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(PATH)
from core import main if __name__ == '__main__':
main.ArgvHandler()

ftp_server.py

 创建一个conf文件,里面包含系统的配置信息,settings.py

  4.1.1.2 conf文件  

IP="127.0.0.1"
PORT=8089

settings.py

  创建一个core文件,里面包含系统的核心代码,main.py和server.py

  4.1.1.3 core文件    

import optparse
#引入optparse模块:其作用是把用户输入的命令匹配成字典形式,参考示例1
import socketserver
#引入socketserver模块:其作用是创建连接对象,启动ftp服务端
from conf import settings
#引入settings模块:其作用是通过配置文件拿到IP地址和端口号
from core import server
#引入server模块:其作用是把主要的逻辑放置到server中,
# 注意:由于main方法不是启动方法,启动方法在bin中,所以需要通过引用的方式实现
class ArgvHandler():
#功能1:用户输入命令-启动ftp_server
def __init__(self):
self.op = optparse.OptionParser()
options, args = self.op.parse_args()
self.verify_args(options, args) def verify_args(self,options, args):
#命令分发,通过反射来实现
cmd=args[0]
if hasattr(self,cmd):
fun=getattr(self,cmd)
fun()
def start(self):
print(" the server is working...")
#启动方法
s=socketserver.ThreadingTCPServer((settings.IP,settings.PORT),server.ServerHandler)
s.serve_forever() '''
示例1:---开始
self.op = optparse.OptionParser()
self.op.add_option("-s", "--server", dest="Server")
self.op.add_option("-p", "--port", dest="Port")
options, args = self.op.parse_args()
print(options)
print(options.Server)
print(args)
示例1在Terminal中输入命令
D:\Code\FTP\FTP_server\bin> python ftp_server.py -s 127.0.0.1 -p 8089 abc
示例1运行结果
{'Server': '127.0.0.1', 'Port': '8089'}
127.0.0.1
['abc']
示例1--结束
'''

main.py

import socketserver
class ServerHandler(socketserver.BaseRequestHandler):
#主要用于服务端的处理方法
def handle(self):
print("ok")

server.py

  创建一个logger文件,主要用户记录日志

  4.1.1.4 logger文件  

    4.1.2 FTP_client

  里面先简单设置一个ftp_client.py的测试客户端  

import socket
sk=socket.socket()
sk.connect(("127.0.0.1",8089))

ftp_client.py

饮冰三年-人工智能-Python-19 Python网络编程的更多相关文章

  1. 饮冰三年-人工智能-Python-10之C#与Python的对比

    1:注释 C# 中 单行注释:// 多行注释:/**/ python 中 单行注释:# 多行注释:“““内容””” 2:字符串 C#中 "" 用双引号如("我是字符串&q ...

  2. 饮冰三年-人工智能-Python-21 Python数据库MySql

    一:下载与安装 1:下载地址:https://dev.mysql.com/downloads/mysql/ 2:安装MySql 打开下载文件解压到指定文件目录.(我这里解压目录为D:\MySql\my ...

  3. 饮冰三年-人工智能-linux-08 软件包管理(Python的安装)

    1:软件包存放的位置 media/CentOS_6.9_Final/Packages文件夹下 2.RPM就是Red Hat Package Manger(红帽软件包管理工具)的缩写. 2.1 常用的命 ...

  4. 饮冰三年-人工智能-Python-22 Python初识Django

    1:一个简单的web框架 # 导包 from wsgiref.simple_server import make_server #自定义个处理函数 def application(environ,st ...

  5. 饮冰三年-人工智能-Python-20 Python线程、进程、线程

    进程:最小的数据单元 线程:最小的执行单元 一: 1:线程1 import threading #线程 import time def Music(): print("Listen Musi ...

  6. 饮冰三年-人工智能-Python-30 python开发中常见的错误

    1:触发条件:创建的实体类生成到数据库表时报错 报错信息:TypeError: __init__() missing 1 required positional argument: 'on_delet ...

  7. 饮冰三年-人工智能-Python-23 Python PyCharm 使用中常见的问题

    一:软件工具使用中遇到的问题 1:AttributeError: module 'pip' has no attribute 'main'问题 处理方法: a:找到JetBrains\PyCharm ...

  8. 饮冰三年-人工智能-Python-18Python面向对象

    1 类与实例对方法和属性的修改 class Chinese: # 这是一个Chinese的类 #定义一个类属性,又称为静态数据或者静态变量,相当于C#中的static country="Ch ...

  9. 饮冰三年-人工智能-Python-17Python基础之模块与包

    一.模块(modue) 简单理解一个.py文件就称之为一个模块. 1.1 模块种类: python标准库 第三方模板 应用程序自定义模块(尽量不要与内置函数重名) 1.2 模块导入方法 # impor ...

随机推荐

  1. mybatis中使用到的设计模式

    Mybatis中使用到了哪些设计模式呢?下面就简单的来介绍下: 1.构造者模式: 构造者模式是在mybatis初始化mapper映射文件的过程中,为<cache>节点创建Cache对象的方 ...

  2. Python基础知识4--数据结构(树)

    树 树的概念 堂兄弟的双亲不一定是兄弟关系. 二叉树 斜树 满二叉树 完全二叉树 二叉树的性质

  3. Starter pom

    以下图片是引用书籍内容: 比如你在用boot写一个web项目,在maven中你会导入: <!-- 导入spring boot的web支持 --> <dependency> &l ...

  4. git 学习(1) ----- git 本地仓库操作

    最近在项目中使用git了,在实战中才知道,以前学习的git 知识只是皮毛,需要重新系统的学一下,读了一本叫  Learn Git in a Month of Lunches 的书籍,这本书通俗易懂,使 ...

  5. 打印并输出 log/日志到文件(C++)

    #include <stdarg.h> #define MAX_LEN 1024 bool debug_mode; // 使用方法同 printf void lprintf(const c ...

  6. JVM运行时内存组成分为一些线程私

    JVM运行时内存组成分为一些线程私有的,其他的是线程共享的. 线程私有 程序计数器:当前线程所执行的字节码的行号指示器. Java虚拟机栈:java方法执行的内存模型,每个方法被执行时都会创建一个栈帧 ...

  7. 并发容器学习—ConcurrentSkipListMap与ConcurrentSkipListSet 原

    一.ConcurrentSkipListMap并发容器 1.ConcurrentSkipListMap的底层数据结构     要学习ConcurrentSkipListMap,首先要知道什么是跳表或跳 ...

  8. C++ Under the Hood

    The original article is taken from http://msdn.microsoft.com/archive/en-us/dnarvc/html/jangrayhood.a ...

  9. 【Noip2015】斗地主

    题目 #include<bits/stdc++.h> using namespace std; int pai[20],T; //pai[]统计牌的数量 int n; int ans; v ...

  10. visual studio 不能跳转到函数定义

    解决办法: 工具-->扩展和更新-->联机.搜索“Go To Definition”下载然后关闭visualstudio进行安装,重启后就ok了