博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
网络编程
阅读量:5124 次
发布时间:2019-06-13

本文共 10274 字,大约阅读时间需要 34 分钟。

一:客户端/服务器架构

1 软件c/s架构

2 网络通信原理:

 

3 互联网协议:

  

 

3socket层

 

4socket是什么:

  

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。

 

5 套接字工作流程

先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束

socket()模块函数用法

 

1 import socket 2 socket.socket(socket_family,socket_type,protocal=0) 3 socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。 4  5 获取tcp/ip套接字 6 tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7  8 获取udp/ip套接字 9 udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)10 11 由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。12 例如tcpSock = socket(AF_INET, SOCK_STREAM)

  

服务端套接字函数 s.bind()    绑定(主机,端口号)到套接字 s.listen()  开始TCP监听 s.accept()  被动接受TCP客户的连接,(阻塞式)等待连接的到来 客户端套接字函数 s.connect()     主动初始化TCP服务器连接 s.connect_ex()  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 公共用途的套接字函数 s.recv()            接收TCP数据 s.send()            发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完) s.sendall()         发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完) s.recvfrom()        接收UDP数据 s.sendto()          发送UDP数据 s.getpeername()     连接到当前套接字的远端的地址 s.getsockname()     当前套接字的地址 s.getsockopt()      返回指定套接字的参数 s.setsockopt()      设置指定套接字的参数 s.close()           关闭套接字 面向锁的套接字方法 s.setblocking()     设置套接字的阻塞与非阻塞模式 s.settimeout()      设置阻塞套接字操作的超时时间 s.gettimeout()      得到阻塞套接字操作的超时时间 面向文件的套接字的函数 s.fileno()          套接字的文件描述符 s.makefile()        创建一个与该套接字相关的文件

 

 二:基于tcp协议通信的套接字(简单版本)

客户端:

import socketphone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.connect(('127.0.0.1',8001))phone.send(b'hello')data=phone.recv(1024)print('就收服务端的消息:',data)

服务端:

import socketphone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.bind(('127.0.0.1',8001))phone.listen(5)print('start------')conn,client_addr=phone.accept()data=conn.recv(1024)print('收到客户的数据',data)conn.send(data.upper())conn.close()phone.close()

 

三:基于tcp协议通信的套接字(通信版本)

客户端:

from socket import *client=socket(AF_INET,SOCK_STREAM)client.connect(('127.0.0.1',8001))while True:    msg=input(">>>").strip()    if len(msg)==0:continue    client.send(msg.encode('utf-8'))    data=client.recv(1024)    print(data)client.close()

服务端

# 服务端必须满足至少三点:# 1 绑定一个固定的ip和port# 2 一直对外提供服务,稳定运行# 3 能够支持并发from socket import *server=socket(AF_INET,SOCK_STREAM)server.bind(('127.0.0.1',8001))server.listen(5)while True:    try:        conn,client_addr=server.accept()        print(client_addr,'连接客户端成功')        while True:            data=conn.recv(1024)            if len(data)==0:break            conn.send(data.upper())        conn.close()    except ConnectionResetError:        break

 

四:基于ssh实现远程执行命令

from socket import *client=socket(AF_INET,SOCK_STREAM)client.connect(('127.0.0.1',8001))while True:    cmd=input(">>>").strip()    if len(cmd)==0:continue    client.send(cmd.encode('utf-8'))    cmd_res=client.recv(1024)    print(cmd_res)client.close()
客户端
from socket import *import subprocessserver=socket(AF_INET,SOCK_STREAM)server.bind(('127.0.0.1',8001))server.listen(5)while True:    conn,client_addr=server.accept()    print(client_addr)    while True:        try:            cmd=conn.recv(1024)            if len(cmd)==0:break            obj=subprocess.Popen(cmd.decode('utf-8'),                                 shell=True,                                 stdout=subprocess.PIPE,                                 stderr=subprocess.PIPE)            stdout=obj.stdout.read()            stderr=obj.stderr.read()            print(len(stdout)+len(stderr))            conn.send(stdout+stderr)        except ConnectionResetError:            break    conn.close()server.close()
服务端

 

五:粘包问题:

from socket import *client=socket(AF_INET,SOCK_STREAM)client.connect(('127.0.0.1',8001))#tcp协议会将数据量小且发送时间间隔较短的数据合并成一个数据报发送client.send(b'hello')client.send(b'andy')client.send(b'hi')
客户端
# 粘包问题是tcp协议流式传输数据的方式导致的# 如何解决粘包问题:接收端能够精确地收干净每个数据包没有任何残留from socket import *import subprocessserver=socket(AF_INET,SOCK_STREAM)server.bind('127.0.0.1',8001)server.listen(5)conn,_=server.accept()datal=conn.recv(5)print('第一次收:',datal)data2=conn.recv(5)print('第二次收:',data2)data3=conn.recv(5)print('第三次收:',data3)
服务端

六:模拟ssh实现远程执行命令(解决编报问题终极版)

from socket import *import json,structclient=socket(AF_INET,SOCK_STREAM)client.connect(('127.0.0.1',8001))while True:    cmd=input('>>>').strip()    if len(cmd)==0:break    client.send(cmd.encode('utf--8'))    # 先接受报头的大小,解出报头的长度    header_zise=struct.unpack('i',client.recv(4))[0]    # 再接收报头    header_bytes=client.recv(header_zise)    header_json=header_bytes.decode('utf-8')    header_dic=json.loads(header_json)    total_size=header_dic['total_size']    print(total_size)    cmd_res=b''    recv_rise=0    while recv_rise
服务端
from socket import *import subprocess,struct,jsonserver=socket(AF_INET,SOCK_STREAM)server.bind(('127.0.0.1',8001))server.listen(5)while True:    conn,client_addr=server.accept()    print(client_addr)    while True:        try:            cmd=conn.recv(1024)            if len(cmd)==0:break            obj=subprocess.Popen(cmd.decode('utf-8'),                                 shell=True,                                 stdout=subprocess.PIPE,                                 stderr=subprocess.PIPE                                 )            stdout=obj.stdout.read()            stderr=obj.stderr.read()            # 制作报头            header_dic={                'filename':'a.txt',                'age':18,                'total_size':len(stdout)+len(stderr)            }            header_json=json.dumps(header_dic)            header_bytes=header_json.encode('utf-8')            # 发送报头的大小            conn.send(struct.pack('i',len(header_bytes)))            # 再发送报头            conn.send(header_bytes)            # 再发送文件主体            conn.send(stdout)            conn.send(stderr)        except ConnectionResetError:            break    conn.close()server.close()
客户端

七:模拟ssh实现远程执行命令(解决粘包问题)

from socket import *import struct,jsonclient=socket(AF_INET,SOCK_STREAM)client.connect(('127.0.0.1'))while True:    cmd=input(">>>").strip()    if len(cmd)==0:continue    client.send(cmd.encode('utf-8'))    header=client.recv(4)    total_size=struct.unpack('i',header)[0]    # 2 接收真正的数据    cmd_res=b''    recv_size=0    while recv_size
客户端
# 服务端必须满足至少三点# 1 绑定一个固定的ip 和 port# 2 一直对外提供服务,稳定运行# 3 能够支持并发from socket import *import subprocessimport structserver=socket(AF_INET,SOCK_STREAM)server.bind(('127.0.0.1'))server.listen(5)# 连接循环while True:    conn,client_addr=server.accept()    print(client_addr)    # 通信循环    while True:        try:            cmd=conn.recv(1024)            if len(cmd)==0:break            obj=subprocess.Popen(cmd.decode('utf-8'),                                 shell=True,                                 stdout=subprocess.PIPE,                                 stderr=subprocess.PIPE                                 )            stdout=obj.stdout.read()            stderr=obj.stderr.read()            # 先制作固定长度的报头            header=struct.pack('i',len(stderr)+len(stdout))            #再发送报头            conn.send(header)            # 3最后发送真是的数据            conn.send(stdout)            conn.send(stderr)        except ConnectionResetError:            break    conn.close()server.close()
服务端

八:基于udp协议通信的套接字

import socketclient=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)while True:    msg=input('>>>').strip()    if len(msg)==0:continue    client.sendto(msg.encode('utf-8'),('127.0.0.1',8001))    data,server_addr=client.recvfrom(1024)    print(data)server.close()
客户端
# 基于tcp通信会将发送的多条数据打包成一个发送过去# 基于udp通信会一条一条的发送数据from socket import *server=socket(AF_INET,SOCK_DGRAM)server.bind(('127.0.0.1',8001))while True:    data,client_addr=server.recvfrom(1024)    print(data)    server.sendto(data.upper(),client_addr)server.close()
服务端

九:数据报协议的特点

from socket import *client=socket(AF_INET,SOCK_DGRAM)client.sendto(b'hello',('127.0.0.1',8001))client.sendto(b'llll',('127.0.0.1',8001))client.sendto(b'hhhhh',('127.0.0.1',8001))
客户端
from socket import *server=socket(AF_INET,SOCK_DGRAM)server.bind(('127.0.0.1',8001))print(server.recvfrom(1024))print(server.recvfrom(1024))print(server.recvfrom(1024))
服务端

十:socketserver模块的使用

1 基于tcp协议通信  

# 基于tcp协议通信socketserverfrom socket import *client=socket(AF_INET,SOCK_STREAM)client.connect(('127.0.0.1',8001))while True:    cmd=input(">>>").strip()    if len(cmd)==0:continue    client.send(cmd.encode('utf-8'))    data=client.recv(1024)    print(data.decode('utf-8'))client.slose()
客户端
import socketserverclass Myhanlder(socketserver.BaseRequestHandler):    def handle(self):        while True:            try:                data=self.request.recv(1024)                if len(data)==0:break                self.request.send(data.upper())            except ConnectionResetError:                break        self.request.close()if __name__ == '__main__':    server=socketserver.ThreadingTCPServer(('127.0.0.1',8001),Myhanlder)    server.serve_forever()
服务端

2 基于udp协议通信

客户端

from socket import *client=socket(AF_INET,SOCK_DGRAM)client.connect(('127.0.0.1',8001))while True:    client.send('hello'.encode('utf-8'))    data=client.recv(1024)    print(data.decode('utf-8'))

 

服务端

# 基于udp协议进行通信socketserver"""import socketserverclass MyUDPhandler(socketserver.BaseRequestHandler):    def handle(self):        data,sock=self.request  # data是接受的发送过来的数据  self.request相当于server        sock.sendto(data.upper(),self.client_address)  # self.client_address 相当于对方的ip和端口if __name__ == '__main__':    server=socketserver.ThreadingUDPServer(('127.0.0.1',8001),MyUDPhandler)    server.serve_forever()"""import socketserverclass MyUDPhandler(socketserver.BaseRequestHandler):    def handle(self):        data,sock=self.request        sock.sendto(data.upper(),self.client_address)if __name__ == '__main__':    server=socketserver.ThreadingUDPServer(('127.0.0.1',8001),MyUDPhandler)    server.serve_forever()

 

ps:egon博客socket编程:http://www.cnblogs.com/linhaifeng/articles/6129246.html

转载于:https://www.cnblogs.com/ouyang99-/p/9600230.html

你可能感兴趣的文章
同步代码时忽略maven项目 target目录
查看>>
Oracle中包的创建
查看>>
团队开发之个人博客八(4月27)
查看>>
发布功能完成
查看>>
【原】小程序常见问题整理
查看>>
C# ITextSharp pdf 自动打印
查看>>
【Java】synchronized与lock的区别
查看>>
django高级应用(分页功能)
查看>>
【转】Linux之printf命令
查看>>
关于PHP会话:session和cookie
查看>>
STM32F10x_RTC秒中断
查看>>
display:none和visiblity:hidden区别
查看>>
C#double转化成字符串 保留小数位数, 不以科学计数法的形式出现。
查看>>
牛的障碍Cow Steeplechase
查看>>
Zookeeper选举算法原理
查看>>
3月29日AM
查看>>
利用IP地址查询接口来查询IP归属地
查看>>
HTML元素定义 ID,Class,Style的优先级
查看>>
构造者模式
查看>>
http和https的区别
查看>>