Python之路PythonNet,第二篇,网络2

pythonnet   网络2

问题:

什么是七层模型
tcp 和udp区别
三次握手和四次挥手
**************************************************

tcp 数据传输:

recv会不断的取出缓冲区中内容,如果一次没有拿完,那么下次会继续收取没拿完的消息;

tcp 粘包

tcp粘包指的是<发送方>  发送若干次数据的时候,因为是数据流的传输方式,导致数据粘在一起,<接收方>一次将多次发送的数据一起接收,传输接收数据的粘连;

粘包是tcp传输特有的现象,因为tcp传输没有消息边界。 如果是发送连续的内容,比如文件等,则粘包没有影响。如果是每次发送为单独需要处理内容则需要处理粘包;

如何处理粘包?

1,将消息格式化;

2,发送消息的同时发送一个消息长度标识;

3,让消息的发送延迟,使接收端每次都能够有时间接收一个消息;

UDP数据表套接字服务端:SERVER

(面向无连接的不可靠的传输服务)

1,创建数据报套接字;

2,绑定本地IP和端口;

3,收发消息;

recvfrom(BUFFERSIZE)

功能:在udp中接收消息;

参数: buffersize 表示一次最多可以接收多少字节的消息;

返回值:data:接收到的消息;

               addr :表示从哪个客户端接收到的消息;

sendto(data, addr)

功能: 向一个网络终端发送消息;

参数:data要发送的消息(bytes)

           addr  发送对象的地址;

4,关闭套接字

import  sys

sys.argv : 将命令行内容收集为一个列表,每个元素是命令行中的一项;

(命令行传入的内容均为str格式; 命令行内容以空格作为分隔,引号可以合成一个整体;)

#!/usr/bin/python3
import sys 

print(sys.argv[1])
print(sys.argv[2])
####
# python3 sys_argv.py  192.168.1.10 8888
192.168.1.10
8888
View Code

UDP客户端:CLIENT

1,创建数据报套接字

2,消息收发;

3,关闭套接字;

(recvfrom每次只能接收一个数据包,如果数据包的大小超过recvfrom的设置大小,则会出现数据丢失;)

########udp_server##########
from socket import * 
import sys 
from time import ctime

#从命令行传入IP和端口
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST,PORT)
BUFFERSIZE = 5

#创建数据报套接字
sockfd = socket(AF_INET,SOCK_DGRAM)

#绑定本地IP和端口
sockfd.bind(ADDR)

#收发消息
while True:
    data,addr = sockfd.recvfrom(BUFFERSIZE)
    print("recv from ",addr,':',data.decode())
    sockfd.sendto\
    (("在 %s 接受到你的消息"%ctime()).encode(),addr)

#关闭套接字
sockfd.close()

############udp_client##############
from socket import *
import sys

#从命令行传入服务器的IP和端口
HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST,PORT)
BUFFERSIZE = 1024

#创建数据报套接字
sockfd = socket(AF_INET,SOCK_DGRAM)

#消息收发
while True:
    data = input("消息>>")
    #输入空客户端退出
    if not data:
        break
    #此处发送消息给服务器
    sockfd.sendto(data.encode(),ADDR)
    data,addr = sockfd.recvfrom(BUFFERSIZE)
    print("从服务器接收:",data.decode())

#关闭套接字
sockfd.close()
###############
python3 udp_client.py 192.168.1.112 8888
message>> a
SERVER recvfrom...:  In Sun Jul  1 17:50:05 2018 recvfrom your messages
####
# python3 udp_server.py 192.168.1.112 8888
recvfrom:  ('192.168.1.112', 56956) : a
View Code

总结tcp和udp的区别:

1,tcp是有连接的,udp是无连接的

2,tcp有三次握手四次挥手的过程;而udp没有;

3,tcp是以数据流传输数据,会有粘包;udp是数据报的形式传输数据,没有粘包;

4,tcp的连接需要消耗一定的资源,相比之下udp资源消耗少;

5,tcp保证数据的可靠性,udp不保证;

6,tcp需要listen  accept   connect; 而   udp 不需要这些操作;

socket模块

套接字属性

getpeername()

功能:用做服务器连接套接字,查看连接的客户端地址;

getsockname()

        功能: 获取套接字对应的绑定的地址和端口; 

s.type  套接字类型

fileno()

    功能:获取套接字的文件描述符号码;

    文件描述符:系统会给进程中的每个IO操作对象匹配一个  >=0 的正整数作为标号,我们称之为该IO操作的文件描述符。一个进程中的所有IO的文件描述符不会重复;

setsockopt(level,  optname,  value)

    功能: 设置套接字选项,可以增加或改变套接字的功能;

    参数:level 要定义的选项类型;

           例如:  SOL_SOCKET  、 IPPROTO_IP、  IPPROTO_TCP

             optname 每种类型都有具体的选项,根据具体需求选择选项 , 进行设置;

             例如: SOL_SOCKET ---> SO_REUSERADDR  (#将端口号设置为立即重用(SOL_SOCKET,SO_REUSEADDR,1) )

             value  将选择的现象设置为什么值;

getsockopt(level, optname)

功能:获取相应选项的值

参数:level 要获取的选项类型

           optname 每种类型都有具体的选项,根据具体需求选择要获取的选项;

返回值:获取到的值;

######tcp_server#####
from socket  import *
import time

HOST = '192.168.1.112'
PORT = 8888 
ADDR = (HOST,PORT)
BUFFERSIZE = 1024

sockfd = socket(AF_INET,SOCK_STREAM)

print("您的套接字是:",sockfd.type)
print("sockfd 的 file num:",sockfd.fileno())

#将端口号设置为立即重用
sockfd.setsockopt\
(SOL_SOCKET,SO_REUSEADDR,1)

print("获取选项值:",sockfd.\
    getsockopt(SOL_SOCKET,SO_REUSEADDR))

sockfd.bind(ADDR)

sockfd.listen(5)

print("您的套接字地址是:",sockfd.getsockname())

while True:
    print("wait for connect......")
    conn,addr = sockfd.accept()
    #使用getpeername获取链接的客户端的地址
    print("connect from ",conn.getpeername())

    while True:
        data = conn.recv(BUFFERSIZE)
        if not data:
            break
        print("接受到:",data.decode())
        n = conn.send(b"Recv your message\n")
        print("发送了 %d 字节的数据"%n)
  
    conn.close()    # 表示和客户端断开连接
    
sockfd.close() # 不能再使用sockfd

######tcp_client######
 cat tcp_client.py 
#!/usr/local/bin/python3

from socket import *
import time

HOST = '192.168.1.112'
PORT = 8888
ADDR = (HOST,PORT)

connfd = socket(AF_INET,SOCK_STREAM)

connfd.connect(ADDR)

while True:
    data = input('send>>>')
    if not data:
        break
    connfd.sendall(data.encode())
    data = connfd.recv(1024)
    print('client recv:',data.decode())

connfd.close()
View Code

socket服务器模型:

硬件服务器 : 计算机主机 IBM HP

集成 分布式

软件服务器 : 网络服务器,提供后端逻辑服务和请求处理的程序集合及架构
例如 web服务器等

服务器架构 c/s b/s 服务器的组织形式

服务器追求 : 更快速, 更安全,并发量更大

fork

1, 创建套接字    绑定    监听;

2,接收客户端连接请求     创建新的进程;

3,主进程继续接收下一个客户端连接请求,子进程处理客户端事件;

4, 有客户端断开,则关闭响应的子进程;

##########fork_tcp_server############
from socket import *
import os 
import signal  

#有客户端断开则关闭相应的子进程
def handler(c):
    while True:
        data = c.recv(BUFFERSIZE).decode()
        if not data:
            break
        print("服务器收到:",data)
        c.send(b'receive your message')
    c.close()
    os._exit(0)

#创建套接字  绑定  监听
HOST = '192.168.1.112'
PORT = 8888
ADDR = (HOST,PORT)
BUFFERSIZE = 1024

#创建tcp套接字
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) 
s.bind(ADDR)
s.listen(5)

#做僵尸进程的处理
signal.signal(signal.SIGCHLD,signal.SIG_IGN)

#接收客户端连接请求  创建新的进程
while True:
    try:
        c,addr = s.accept()
    except KeyboardInterrupt:
        print("服务器结束")
        s.close()
        os._exit(0)
    except Exception:
        continue
    print("接收到客户端链接 >",c.getpeername())

    pid = os.fork()
   
    if pid < 0:
        print("创建子进程失败")
        continue
    #子进程处理客户端事件
    elif pid == 0:
        s.close()
        print('处理客户端请求事件')
        handler(c) # 处理客户端的函数
    #主进程继续接收下一个客户端连接请求
    else:
        c.close()
        continue

#########tcp_client########
# cat tcp_server.py 
#!/usr/local/bin/python3

from socket import *

HOST = '127.0.0.1'
PORT = 8888
ADDR = (HOST,PORT)
BUFFERSIZE = 1024

sockfd = socket(AF_INET, SOCK_STREAM)

sockfd.bind(ADDR)

sockfd.listen(5)

while True:
    print('wait for connect....')

    conn,addr = sockfd.accept()
    print('connect from',addr)
    while True: 
        data = conn.recv(BUFFERSIZE)
        if not data:
            break
        print('connect:',data.decode())
        n = conn.send(b'Recv your message.\n')
        print('send.. %d'%n)
    conn.close()

sockfd.close()
View Code

threading

1, 创建套接字  , 绑定, 监听;

2,接收客户端连接请求, 创建新的线程;

3,主线程继续接收下一个客户端连接请求;分支线程处理客户端事件;

练习

########threading_tcp_server#######
from socket import *
import threading
import os

#有客户端断开则关闭相应的子线程
def handler(c):
    while True:
        data = c.recv(BUFFERSIZE).decode()
        if not data:
            break
        print("服务器收到:",data)
        c.send(b'receive your message')
    c.close()

#创建套接字  绑定  监听

HOST = '127.0.0.1'
PORT = 8888
ADDR = (HOST,PORT)
BUFFERSIZE = 1024

#创建tcp套接字
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) 
s.bind(ADDR)
s.listen(5)

#接收客户端连接请求  创建新的线程
while True:
    try:
        c,addr = s.accept()
    except KeyboardInterrupt:
        print("服务器结束")
        s.close()
        os._exit(0)
    except Exception:
        continue
    print("接收到客户端链接 >",c.getpeername())

    #分支线程处理客户端事件
    t = threading.Thread\
    (target = handler,args = (c,))
    t.setDaemon(True)
    t.start()

  
    #主线程继续接收下一个客户端连接请求

##########tcp_client#################
# cat tcp_client.py
#!/usr/local/bin/python3

from socket import *
import time

HOST = '127.0.0.1'
PORT = 8888
ADDR = (HOST,PORT)

connfd = socket(AF_INET,SOCK_STREAM)

connfd.connect(ADDR)

while True:
    data = input('send>>>')
    if not data:
        break
    connfd.sendall(data.encode())
    data = connfd.recv(1024)
    print('client recv:',data.decode())

connfd.close()
View Code

socketserver模块 (python2 SocketServer)

'DatagramRequestHandler',
'ForkingMixIn',
'ForkingTCPServer',
'ForkingUDPServer',
'StreamRequestHandler',
'TCPServer',
'ThreadingMixIn',
'ThreadingTCPServer',
'ThreadingUDPServer',
'UDPServer',

三部分:

多进程/多线程             TCP/UDP                  streamhandler/datagramhandler

ForkingMixIn                 TCPServer                      StreamRequestHandler

ThreadingMixIn             UDPServer                      DatagramRequestHandler

组合如下:

‘ThreadingTCPServer’   =  ThreadingMixIn   + TCPServer

‘ThreadingUDPServer’   =  ThreadingMixIn  + UDPServer

ForkingTCPServer   =  ForkingMixIn   + TCPServer

 ForkingUDPServer = ForkingMixIn   + UDPServer

步骤:

1, 创建服务器类;

2,创建处理类;

3,使用创建的服务器类来生产服务器;

# fork + tcp 并发

########socket_server#########
# fork + tcp 并发

from socketserver import *

#创建服务器类
class Server(ThreadingMixIn,TCPServer):
    pass

# class Server(ForkingTCPServer):
#     pass

#创建处理类
class Handler(StreamRequestHandler):
    #当有客户端链接时候调用该函数自动处理
    #客户段请求事件
    def handle(self):
        print("connect from ",self.client_address)
        while True:
            #self.request 为tcp中为我们自动生成的
            #和客户端交互的套接字
            data = self.request.recv(1024).decode()
            if not data:
                break
            print("服务器收到:",data)
            self.request.send(b'receive your message')

#使用创建的服务器类来生产服务器
server = Server(('172.60.50.218',9999),Handler)
#运行服务器
server.serve_forever()
#########tcp_client########
# cat tcp_client.py 
#!/usr/local/bin/python3

from socket import *
import time

HOST = '127.0.0.1'
PORT = 8889
ADDR = (HOST,PORT)

connfd = socket(AF_INET,SOCK_STREAM)

connfd.connect(ADDR)

while True:
    data = input('send>>>')
    if not data:
        break
    connfd.sendall(data.encode())
    data = connfd.recv(1024)
    print('client recv:',data.decode())

connfd.close()
View Code

# fork + udp

##########fork_udp_server#############
# fork  + udp 

from  socketserver import *

class Server(ForkingUDPServer):
    pass

class Handler(DatagramRequestHandler):
    #udp无连接所以request的含义不同
    def handle(self):
        data = self.rfile.readline()
        print("接受到了:",data.decode())
        self.wfile.write(b"receive message")

server = Server(('0.0.0.0',8888),Handler)
server.serve_forever()
###########udp_client##############
# cat udp_client.py
#!/usr/local/bin/python3

from socket import *
import sys

HOST = sys.argv[1]
PORT = int(sys.argv[2])
ADDR = (HOST,PORT)
BUFFERSIZE = 1024

sockfd = socket(AF_INET, SOCK_DGRAM)

while True:
    data = input("message>> ") 
    if not data:
        break
    sockfd.sendto(data.encode(),ADDR)
    data,addr = sockfd.recvfrom(BUFFERSIZE)
    print('SERVER recvfrom...: ', data.decode())

sockfd.close() 
View Code

思考:ftp传输

猜你喜欢

转载自www.cnblogs.com/weizitianming/p/9221662.html