scoket

## 简介

  1. WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC
    6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
  2. WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket
    API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
三次握手

在这里插入图片描述

(1)第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
(2)第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
(3)第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

⑤SYN攻击:

在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open
connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将产时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击时一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了。

使用如下命令可以让之现行:#netstat -nap | grep SYN_RECV ⑥TCP连接的建立:SYN分节
终止:FIN(finish)分节

四次挥手

在这里插入图片描述

由于TCP连接是全双工的,每个方向都必须要单独进行关闭,原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。

(1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
(2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server入CLOSE_WAIT状态。
(3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
(4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

TCP(C/S)流程图

在这里插入图片描述

①TCP是一种精致的,可靠的字节流协议。

②在TCP编程中,三路握手一般由客户端(Client)调用Connent函数发起。

③TCP3次握手后数据收发通道即打开(即建立了连接)。

TCP群聊(Server端工作原理)
import socket, threading, logging, datetime
FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s'
logging.basicConfig(format=FORMAT, level=logging.INFO)


class Sserver():
    def __init__(self, ip='127.0.0.1', port=8888):
        self.addr = (ip, port)
        self.sock = socket.socket()
        self.cliens = {}
        self.event = threading.Event()

    def start(self):
        self.sock.bind(self.addr)
        self.sock.listen()
        threading.Thread(target=self.accept, name='accept').start()

    def accept(self):
        while not self.event.is_set():
            s, raddr = self.sock.accept()
            logging.info(raddr)
            logging.info(s)
            self.cliens[raddr] = s
            threading.Thread(target=self.recv, name='recv', args=(s, )).start()

    def recv(self, sock:socket.socket):
        while True: 
            try:
                data = sock.recv(1024)
            except expression as e:
                logging.error(e)
                data = b'quit'
            if data == b'quit':
                self.cliens.pop(sock.getpeername())
                sock.close()
                break

            msg = 'bak{}. {} {}'.format(
                sock.getpeername(),
                datetime.datetime.now().strftime("%Y/%m/%d-%H:%M:%S"), 
                data.decode()).encode()
            for s in self.cliens.values():
                s.send(msg)

    def stop(self):
        for s in self.cliens.values():
            s.close()
        self.sock.close()


cs = Sserver()
cs.start()

while True:
    cmd = input('>>>>  ')
    if cmd.strip() == 'quit':
        cs.stop()
        threading.Event.wait(3)
        break
    logging.info(threading.enumerate())

TCP群聊进阶(socket对象转换为文件)

import socket, threading, logging, datetime

FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s'
logging.basicConfig(format=FORMAT, level=logging.INFO)


class Sserver():
    def __init__(self, ip='127.0.0.1', port=8888):
        self.addr = (ip, port)
        self.sock = socket.socket()
        self.cliens = {}
        self.event = threading.Event()

    def start(self):
        self.sock.bind(self.addr)
        self.sock.listen()
        threading.Thread(target=self.accept, name='accept').start()

    def accept(self):
        while not self.event.is_set():
            s, raddr = self.sock.accept()
            f = s.makefile(mode='rw')
            logging.info(raddr)
            logging.info(s)
            logging.info(f)
            self.cliens[raddr] = f
            threading.Thread(target=self.recv, name='recv', args=(f, raddr)).start()

    def recv(self, f, addr):
        while True: 
            try:
                # data = sock.recv(1024)
                data = f.readline()
                logging.info(data)
            except expression as e:
                logging.error(e)
                data = b'quit'
            if data == b'quit':
                self.cliens.pop(addr)
                f.close()
                break
            msg = 'bak{}. {} {}'.format(
                addr,
                datetime.datetime.now().strftime("%Y/%m/%d-%H:%M:%S"), 
                data.decode()).encode()
            for s in self.cliens.values():
                f.write(msg)
                f.flush()

    def stop(self):
        for s in self.cliens.values():
            s.close()
        self.sock.close()
        self.event.set()


def main():
    cs = Sserver()
    cs.start()

    while True:
        cmd = input('>>>>  ')
        if cmd.strip() == 'quit':
            cs.stop()
            threading.Event.wait(3)
            break
        logging.info(threading.enumerate())

if __name__ == '__main__':
    main()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值