网络编程知识点剖析

网络编程知识点剖析

. C/S 架构: Client / Server  客户端 / 服务端

    B/S 架构: Browser / Server  前端 / 服务端

 

.网络编程通信流程.

  网卡   mac地址   IP地址   子网掩码   网关   DNS服务器  (进行域名(domain name)和与之相对应的IP地址 (IP address)转换的服务器。)  

  DHCP (自动分配IP)    NAT (Network Address Translation,网络地址转换)  端口   路由器

     交换机   集线器   广播 单播 广播风暴   arp协议(地址解析协议)    路由协议

 

.网络通信协议

 1. osi七层:            tcp\ ip 五层:

      应用层              应用层  

      表示层              传输层

      会话层              网路层

      传输层              数据链路层

      网络层              物理层

      数据链路层

      物理层

  2. TCP\IP 协议存在 传输层   

    Tcp   : 面向连接,消息可靠,效率相对差,面向流的消息格式,无消息保护边界    

    Udp  : 面向无连接,消息不可靠,效率高,面向包的消息格式,有消息保护边界

    tcp三次握手:1.(client) > [SYN包 ]->(server)   请求建立连接

          2.(client) < [SYN/ACK] < (server)  severs收到syn 发送[SYN/ACK]确认包

          3.(client)> [ACK] >(server)  client收到[SYN/ACK] 在发一个[ACK]确认包

    tcp四次挥手:1.(client) > [ACK/FIN] >(server) 发送包 请求关闭

          2.(client) < [ACK] <(server)  收到包  同意关闭

          3.(client) <[ACK/FIN] <(server) 收到包   是否收到 同意关闭 消息 

          4.(client) > [ACK/FIN] >(server)  发送包  收到过程2的消息,

四.socket

  1. 服务端与客户端 手法消息 基本结构

server>>>>>>>>>>>>>>>>>

import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8898))  #把地址绑定到套接字
sk.listen()          #监听链接
conn,addr = sk.accept() #接受客户端链接
ret = conn.recv(1024)  #接收客户端信息
print(ret)       #打印客户端信息
conn.send(b'hi')        #向客户端发送信息
conn.close()       #关闭客户端套接字
sk.close()        #关闭服务器套接字(可选)

client>>>>>>>>>>>>>>>>
import socket
sk = socket.socket()           # 创建客户套接字
sk.connect(('127.0.0.1',8898))    # 尝试连接服务器
sk.send(b'hello!')
ret = sk.recv(1024)         # 对话(发送/接收)
print(ret)
sk.close()            # 关闭客户套接字
tcp 服务端和客户端通信 基本代码

 

server>>>>>>>>>>>>>>>>>>>>>>>>

import socket
udp_sk = socket.socket(type=socket.SOCK_DGRAM)   #创建一个服务器的套接字
udp_sk.bind(('127.0.0.1',9000))        #绑定服务器套接字
msg,addr = udp_sk.recvfrom(1024)
print(msg)
udp_sk.sendto(b'hi',addr)                 # 对话(接收与发送)
udp_sk.close()                         # 关闭服务器套接字

client>>>>>>>>>>>>>>>>>>>>>>>>

import socket
ip_port=('127.0.0.1',9000)
udp_sk=socket.socket(type=socket.SOCK_DGRAM)
udp_sk.sendto(b'hello',ip_port)
back_msg,addr=udp_sk.recvfrom(1024)
print(back_msg.decode('utf-8'),addr)
udp

  2.缓冲区

     作用:  提高效率,将发送或者接受信息的过程与网络传输隔离开,解耦

    特性:  1.I/O缓冲区在每个TCP套接字中单独存在;
         2.I/O缓冲区在创建套接字时自动生成;
         3.即使关闭套接字也会继续传送输出缓冲区中遗留的数据;
         4.关闭套接字将丢失输入缓冲区中的数据。
    大小:  一般默认为 8K, 可以通过 getsockopt() 函数获取

  3.粘包

    TCP会粘包、UDP永远不会粘包

    粘包的两种现象: 

    1.连续发送小包并且间隔时间很短,就会发送两个消息合并在一起的情况,被一次接受了,(Nagel 优化算法导致的,            避免连续发送小包,影响传输xiaol)

    2.一次发送数据过大,对方一次未接受完导致下次接受的时候,连同第一次剩下的消息,一同接受了,导致粘包.

    解决粘包的方案: 

      原因是因为双方不知道对方发送的消息长度

    1.发送消息之前先发送消息的长度,然后收到对方的确认信息后再发送消息.

    2.通过struct模块,自定义包头,将消息长度打包成4个字节长度的信息,连同你要发送的数据,一起发送过去

      打包:pack('i',长度) 长度是个整数

      解包:unpack('i',接受的那4个字节),得到的是元祖

    Sendall(): 循环的send直到数据发送完毕.

    Socketsserver(): 实现tcp协议下,一个服务端可以同时和多个客户端进行通信.

 

import socket,struct,json
import subprocess
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

phone.bind(('127.0.0.1',8080))
phone.listen(5)

while True:
    conn,addr=phone.accept()
    while True:
        cmd=conn.recv(1024)
        if not cmd:break
        print('cmd: %s' %cmd)

        res=subprocess.Popen(cmd.decode('utf-8'),
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        err=res.stderr.read()
        print(err)
        if err:
            back_msg=err
        else:
            back_msg=res.stdout.read()

        headers={'data_size':len(back_msg)}
        head_json=json.dumps(headers)
        head_json_bytes=bytes(head_json,encoding='utf-8')

        conn.send(struct.pack('i',len(head_json_bytes))) #先发报头的长度
        conn.send(head_json_bytes) #再发报头
        conn.sendall(back_msg) #在发真实的内容

    conn.close()
解决粘包方案一 server
import socket
import struct,json
client= socket.socket()
client.connect(("127.0.0.1",8080))

while True:
    cmd=input(">>: ")
    if not cmd:continue
    client.send(bytes(cmd,encoding='utf-8'))

    head=client.recv(4)
    head_json_len=struct.unpack('i',head)[0]
    head_json=json.loads(client.recv(head_json_len).decode('utf-8'))
    data_len=head_json['data_size']

    recv_size=0
    recv_data=b''
    while recv_size < data_len:
        recv_data = client.recv(1024) + recv_data
        recv_size = len(recv_data) + recv_size

    print(recv_data.decode('gbk'))
解决粘包解决方案一 client

 

import socketserver
class Myserver(socketserver.BaseRequestHandler):
    def handle(self):
        self.data = self.request.recv(1024).strip()
        print("{} wrote:".format(self.client_address[0]))
        print(self.data)
        self.request.sendall(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "127.0.0.1", 9999

    # 设置allow_reuse_address允许服务器重用地址
    socketserver.TCPServer.allow_reuse_address = True
    # 创建一个server, 将服务地址绑定到127.0.0.1:9999
    #server = socketserver.TCPServer((HOST, PORT),Myserver)
    server = socketserver.ThreadingTCPServer((HOST, PORT),Myserver)
    # 让server永远运行下去,除非强制停止程序
    server.serve_forever()
tcp_server_sockserver
import socket

HOST, PORT = "127.0.0.1", 9999
data = "hello"

# 创建一个socket链接,SOCK_STREAM代表使用TCP协议
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    sock.connect((HOST, PORT))          # 链接到客户端
    sock.sendall(bytes(data + "\n", "utf-8")) # 向服务端发送数据
    received = str(sock.recv(1024), "utf-8")# 从服务端接收数据

print("Sent:     {}".format(data))
print("Received: {}".format(received))
tcp_client_socketserver

 

  

posted @ 2018-11-03 22:41  孔辉  阅读(280)  评论(0编辑  收藏  举报