1 2 3 4

TCP协议 三次握手,四次挥手,socket 粘包

TCP协议 三次握手,四次挥手,socket 粘包

TCP协议

1.协议是建立双向的管道

传输层的:

​ -TCP协议

​ -UDP协议

1.1三次握手,建连结

​ 1.客户端向服务端发送建立连结的请求;

​ 2.服务端返回收到请求的信息给客户端,并且发送往客户端建立连接的请求;

​ 3.客户端接收到服务发来的请求,返回连接成功给服务层,完成双向的连接。

1.2反馈机制

​ 1.客户端往服务端发送请求,服务端必须返回响应;

​ 2.告诉客户端收到请求了,并且将服务端色数据一并返回给客户端。

​ C---->S:一次的请求,必须有一次的响应

​ 缺点:

​ -洪水攻击:

​ 指的通过伪造大量的请求,往对方的服务器发送请求;

​ 导致对方服务器想用跟不上,以至于瘫痪;

​ linux系统有个参数可以限制

​ -半连接池listen:限制用户的在同一个时间段内的访问数量。

1.3四次挥手,断开连接

​ 1.客户端向服务端发送断开连接的请求;

​ 2.服务端返回收到请求的信息给客户端;

​ 3.服务端确认所有的数据发送完成以后,再发送同意断开来连接的请求给用户端;

​ 4.客户端返回收到断开的连接的请求,给服务端。

socket

-定义:

​ socket是一个模块,又称套接字,用来封装互联网协议(应用层以下的层)

-作用:

​ -socket可以实现 互联网协议的应用层以下的层的工作;

​ -提高开发效率

​ -怎么使用:

​ import socket

​ 写socket 套接字

​ Client

​ Server

​ 注意:

​ 端口:port 标识一台电脑计算机上的某一个软件

​ -0-1024禁止使用,操作系通在用

​ -软件的固定端口不要用:

​ django:8000

​ mysql:3306

​ flask:5000

​ redis:6379

​ tomcat:8080

​ mongodb:27017

下面这个是个socket的最总版本

先执行server 再去执行client

'''
注意:客户端先发一次发送,服务端的先一次接受,再发送信息  server
'''
import socket
#买手机   socket 也是一个类
server = socket.socket()
#绑定手机卡
server.bind(
    ('127.0.0.1',9528)
)#####127.0.0.1 是本地的回环地址
####局域网内测试的是192.168.12.202 ,9527
#半连接池
server.listen(5)##按照今天举得例子,最多5个人坐椅子,一个人在享受服务,实际是6个人
print('server is running....')
#循环实现可接受多个用户访问
#等待电话接入————>接入客户端
#conn 指的是服务端往客户端的管道
while True:
    conn,addr = server.accept()
    print(addr)

#循环实现通信
    while True:
        try: #监听代码块是否有异常
            #接收对方讲话的内容
            #data客户端端发来的信息
            data = conn.recv(1024) #一次可以接收1024bytes
            if len(data) == 0:
                break
            if data.decode('utf-8') =='q':
                break
            print(data.decode('utf-8'))   ###这个是传过来的时候是编码用utf-8编码的,解码也要用这个解码
            send_data = input('服务端>>>:')
            #服务端往客户端发送信息
            conn.send(send_data.encode('utf-8'))
            #捕获异常的信息,并打印,报错信息
        except Exception as e:
            print(e)
            break

    #挂电话
    conn.close()
 

下面这个是client
    # '''
# 启动服务端后再启动客户端
# '''
import socket
#买手机
client = socket.socket()
#拨号
client.connect(
    ('127.0.0.1',9528)
)#客户端的ip和port必须和服务器保持一致
print('client is running....')

#必须发送bytes类型的数据
#必须讲给对方听
while True:
    send_data = input('客户端>>>>:')
    client.send(send_data.encode('utf -8'))
    data = client.recv(1024)

    if data .decode('utf-8') == 'q':
        break

    if len(data) == 0:
        break
    print(data.decode('utf-8'))
client.close()



粘包问题

出现的问题:

1.无法确认对方发来的数据的大小

2.在发送数据间隔短并且数量小的情况下,会将所有数据一次性发送

解决办法

-粘包(struct模块)

​ -无论那一端发送数据

​ -客户端:

​ 1.先制作报头,在发生

​ 2.发送真实的数据

​ -服务端

​ 1.接收报头,并解包获取真实的长度 recv(报头)

​ 2.根据真实的长度,接收真实的数据 recv(真实的数据长度)

粘包的举例 电影

先执行server 再去执行client

下面这个server

import socket
import json
import struct
server = socket.socket()
server.bind(
    ('127.0.0.1',9002)
)
server.listen(5)
while True:
    conn,addr = server.accept()
    print(addr)
    while True:
        try:
            #获取客户传过来的报头
            header = conn.recv(4)
            #解包获取真实的数据长度
            json_len = struct.unpack('i',header)[0]
            #接收json的真实长度
            json_bytes_data = conn.recv(json_len)
            #将bytes类型转化成json数据
            json_data = json_bytes_data.decode('utf-8')
            #反序列化
            back_dic = json.loads(json_data)
            print(back_dic)
            print(back_dic.get('movie_len'))

            # movie_data = conn.recv(back_dic.get('movie_len'))
            # print(movie_data)
        except Exception as e:
            print(e)
            break
    conn.close()
    >>>>>>>>>>>>>>>>>>>>>
    ('127.0.0.1', 53140)
{'movie_name': '太阳', 'movie_len': 100000}
100000
{'movie_name': '中国', 'movie_len': 100000}
100000
    
    下面这个是client
    
    import socket
import struct
import json

client = socket.socket()
client.connect(
    ('127.0.0.1',9002)
)
while True:
    movie_name = input('请输入电影的名字:')
    #伪装的一个电影的真实长度
    movie_len = 100000
    send_dic = {
        'movie_name': movie_name,
        'movie_len': movie_len
    }
    #序列化
    json1 = json.dumps(send_dic)
    print(json1)
    print(json1.encode('utf-8'))
    print(len(json1.encode('utf-8')))
    json1_bytes = json1.encode('utf-8')
    #做一个报头
    header = struct.pack('i',len(json1_bytes))
    #先发送包头
    client.send(header)
    #再发送真实的数据
    client.send(json1_bytes)
>>>>>>>>>>>>>>>>>>>>>>
请输入电影的名字:太阳
{"movie_name": "\u592a\u9633", "movie_len": 100000}
b'{"movie_name": "\\u592a\\u9633", "movie_len": 100000}'
51
请输入电影的名字:中国
{"movie_name": "\u4e2d\u56fd", "movie_len": 100000}
b'{"movie_name": "\\u4e2d\\u56fd", "movie_len": 100000}'
51

与终端的相关联的举例

下面这个是server

import socket
import subprocess

server = socket.socket()
server.bind(
    ('127.0.0.1',9000)
)

server.listen(5)
while True:
    conn,addr = server.accept()

    while True:
        try:
            cmd = conn.recv(10)

            if len(cmd) == 0:
                continue
            cmd = cmd.decode('utf-8')
            if cmd == 'q':
                break
            #调用subprocess连接终端,对终端进行操作,并获取操作后正确或者错误的结果
            obj = subprocess.Popen(
                cmd,shell = True,
                stdout = subprocess.PIPE,
                stderr = subprocess.PIPE,
            )
            #结果交给result变量名
            result = obj.stdout.read()+obj.stderr.read()####stuout是正确的结果,stuerr是错误的结果,这个result 是正确的和错误的相加,无论对错都能打印一个结果
            print(len(result))
            #gbk
            print(result.decode('gbk'))  ###window系统 终端默认的编码是gbk
            conn.send(result)

        except Exception as e:
            print(e)
            break
            
            
  下面这个是client
import socket
client = socket.socket()
client.connect(
    ('127.0.0.1',9000)
)
while  True:
    cmd = input('客户输入的内容:')
    client.send(cmd.encode('utf-8'))
    data = client.recv(19190)
    print(len(data))
    print(data.decode('gbk'))

posted @ 2019-12-06 20:03  ^更上一层楼$  阅读(139)  评论(0编辑  收藏  举报