Socket 长连接 (一)

564 阅读6分钟

背景:公司在线客服老代码多线程数据安全问题严重,以及层级之间互相调用,导致了严重的耦合。对项目进行相应的重构。

  • 什么是socket,什么是Http,他们之间的区别。
  • 项目搭建的架构是什么样子的。相应架构层级之间的关系。以及每一个层级之间的关系。
  • 即时通讯 的特性有哪些。如何保证这些特性的。用到了相应的什么技术。

今天第一篇就讨论socket , HTTP 和 TCP 之间的关系。

说到socket,必不可少的我们要说到网络登记,各个模块。我们众所周知,网络层级有四层模型,和七层模型。

我这里直接说网络四层模型了。图形化可以参考这篇文章:blog.csdn.net/cc1949/arti…

到底有哪四层呢?应用层,传输层,会话层,链路层。一般的HTTP (超文本传输协议) 是在应用层的。而socket 则不是,socket传输层上面的一个套接字。

  • 应用层:一般就是http 报文(其他一些协议,例如:邮件)

  • 传输层:我们一般是拿来建立端口到端口的通信(比如进程和进程之间的)。

  • 网络层:主机到主机。(在网络中确定)通过IP + Mac地址。

  • 数据链路层:MAC地址。

了解Socket 之前要对相应的TCP 头了解

源端口号:占2字节

目标端口:占2字节

序号:每次发送数据都要打上一个记号,可以在目标端口那里收到数据后,按照一定顺序组装。

确认号:序号字段值的开始位置,通过计算收到的data得到相应的数据长度。然后用数据长度 加上相应的一个序号。

**数据偏移:**占4个比特位,【0,15】。 偏移的是4字节的倍数,所以【0,60】。

保留:暂时没用

URG: 紧急处理,收到之后一般不会加在缓冲区末尾,只会加在缓冲区前面。比如 control + c

ACK: 只有连接之后才有用,连接之后报文会将ACK 设置为 1。

PSH: 发送方希望尽快发送

RST: 复位,连接错误。当接受到rst ,会立即通知程序连接被复位。然后断开连接。

SYN: 连接建立的过程,用于同步序列号,告知对方自己的起始序列号。根据对方的序列号初始化自己的缓冲区起点。

FIN: 用于表示数据发送完毕,等待关闭连接

窗口: 发送报文方,能够接受的字节数。

上面基本傻姑娘就是TCP 头的一些重要信息。

TCP 的特性是啥?

一般有下面几个特性,面向连接,可靠,无差错,顺序性,面向字节流。

  • 建立连接: 建立一定的数据结构,来维护双方交互的状态,保证连接的特性。(至于什么样的数据结构,先挖个坑,以后埋)
  • 连接: 两端数据结构的协同,能够对的上就是连接着的。对不上,就是断开。
  • 可靠: 数据结构在点名。
  • 顺序性: 数据结构在排名。
  • 面向数据流: 按顺序捏成一个数据流,发送给应用层。

大概知道TCP 了之后,紧接着就是想知道Socket 到底是啥呢?

Socket 是套接字,不属于网络分层结构,但是我们可以把它理解成 用户态 和 操作系统内核态的一个必须要经过的一个转接口。

既然是一个转接口,那么我们如何用这个转接口呢?从iOS 的角度看:

struct sockaddr_in6 {
	__uint8_t       sin6_len;       /* length of this struct(sa_family_t) */
	sa_family_t     sin6_family;    /* AF_INET6 (sa_family_t) */
	in_port_t       sin6_port;      /* Transport layer port # (in_port_t) */
	__uint32_t      sin6_flowinfo;  /* IP6 flow information */
	struct in6_addr sin6_addr;      /* IP6 address */
	__uint32_t      sin6_scope_id;  /* scope zone index */
};

从上面的数据接口我们应该能够找到一下比较重要的:比如 family , port , addr 。一般其他语言相应的也会有一些结构体,让咱们使用,但是肯定少不了这三个要素。我们从连接socket 的函数也能看出来。

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

针对TCP 层进行编程

  • 我们调用Connect()函数进行连接。
  • 紧接着进行三次握手。(完成连接)

我们通过 connect() 函数 连接,然后经过TCP 的三次握手,

image-20200521155744174.png

应用层是不需要进行参与的。这个时候socket 我们就就建立了。

还记得开文提出的socket 和 http 的区别吗,他们之间不能说区别,倒是可以说一说关系,这是一个坑点。我们用的http 是应用层的,那么我们在应用层完成报文后,是通过socket 抛送给应用层。这里倒是可以说的通一点。

补充

  • connect 函数详解

    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    
    • sockfd 是socket 的一个编号,系统中我们创建一个socket 然后返回一个编号,我们可以通过这个编号拿到相应的socket。我们可以通过如下函数进行创建。

       int socketFD = socket(family, SOCK_STREAM, 0);
      
    • socketaddr 是一个包含host ,port 的一个结构体

    • 数据长度

  • socketAddr 结构体是啥样?

    struct sockaddr {//16
    	__uint8_t       sa_len;         /* total length */
    	sa_family_t     sa_family;      /* [XSI] address family */
    	char            sa_data[14];    /* [XSI] addr value (actually larger) */
    };
    
    
    
  • sockaddr_in

    struct sockaddr_in {//16
    	__uint8_t       sin_len; // 1
    	sa_family_t     sin_family; //1
    	in_port_t       sin_port; //2
    	struct  in_addr sin_addr; //4
    	char            sin_zero[8];//8
    };
    
struct sockaddr_in6 {//16
	__uint8_t       sin6_len; //1      /* length of this struct(sa_family_t) */
	sa_family_t     sin6_family; //1   /* AF_INET6 (sa_family_t) */
	in_port_t       sin6_port;//2      /* Transport layer port # (in_port_t) */
	__uint32_t      sin6_flowinfo;//4  /* IP6 flow information */
	struct in6_addr sin6_addr;//4      /* IP6 address */
	__uint32_t      sin6_scope_id;//4  /* scope zone index */
};

最后会传入这样一个结构体给到底部。上面的结构体可以相互转化。

iOS 的同学可看

/*
 * Address families.
 */
#define AF_UNSPEC       0               /* unspecified */
#define AF_UNIX         1               /* local to host (pipes) */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define AF_LOCAL        AF_UNIX         /* backward compatibility */
#endif  /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define AF_INET         2               /* internetwork: UDP, TCP, etc. */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define AF_IMPLINK      3               /* arpanet imp addresses */
#define AF_PUP          4               /* pup protocols: e.g. BSP */
#define AF_CHAOS        5               /* mit CHAOS protocols */
#define AF_NS           6               /* XEROX NS protocols */
#define AF_ISO          7               /* ISO protocols */
#define AF_OSI          AF_ISO
#define AF_ECMA         8               /* European computer manufacturers */
#define AF_DATAKIT      9               /* datakit protocols */
#define AF_CCITT        10              /* CCITT protocols, X.25 etc */
#define AF_SNA          11              /* IBM SNA */
#define AF_DECnet       12              /* DECnet */
#define AF_DLI          13              /* DEC Direct data link interface */
#define AF_LAT          14              /* LAT */
#define AF_HYLINK       15              /* NSC Hyperchannel */
#define AF_APPLETALK    16              /* Apple Talk */
#define AF_ROUTE        17              /* Internal Routing Protocol */
#define AF_LINK         18              /* Link layer interface */
#define pseudo_AF_XTP   19              /* eXpress Transfer Protocol (no AF) */
#define AF_COIP         20              /* connection-oriented IP, aka ST II */
#define AF_CNT          21              /* Computer Network Technology */
#define pseudo_AF_RTIP  22              /* Help Identify RTIP packets */
#define AF_IPX          23              /* Novell Internet Protocol */
#define AF_SIP          24              /* Simple Internet Protocol */
#define pseudo_AF_PIP   25              /* Help Identify PIP packets */
#define AF_NDRV         27              /* Network Driver 'raw' access */
#define AF_ISDN         28              /* Integrated Services Digital Network */
#define AF_E164         AF_ISDN         /* CCITT E.164 recommendation */
#define pseudo_AF_KEY   29              /* Internal key-management function */
#endif  /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define AF_INET6        30              /* IPv6 */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define AF_NATM         31              /* native ATM access */
#define AF_SYSTEM       32              /* Kernel event messages */
#define AF_NETBIOS      33              /* NetBIOS */
#define AF_PPP          34              /* PPP communication protocol */
#define pseudo_AF_HDRCMPLT 35           /* Used by BPF to not rewrite headers
	                                 *  in interface output routine */
#define AF_RESERVED_36  36              /* Reserved for internal usage */
#define AF_IEEE80211    37              /* IEEE 802.11 protocol */
#define AF_UTUN         38
#define AF_MAX          40
#endif  /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
/*
 * Option flags per-socket.
 */
#define SO_DEBUG        0x0001          /* turn on debugging info recording */
#define SO_ACCEPTCONN   0x0002          /* socket has had listen() */
#define SO_REUSEADDR    0x0004          /* allow local address reuse */
#define SO_KEEPALIVE    0x0008          /* keep connections alive */
#define SO_DONTROUTE    0x0010          /* just use interface addresses */
#define SO_BROADCAST    0x0020          /* permit sending of broadcast msgs */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define SO_USELOOPBACK  0x0040          /* bypass hardware when possible */
#define SO_LINGER       0x0080          /* linger on close if data present (in ticks) */
#else
#define SO_LINGER       0x1080          /* linger on close if data present (in seconds) */
#endif  /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define SO_OOBINLINE    0x0100          /* leave received OOB data in line */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define SO_REUSEPORT    0x0200          /* allow local address & port reuse */
#define SO_TIMESTAMP    0x0400          /* timestamp received dgram traffic */
#define SO_TIMESTAMP_MONOTONIC  0x0800  /* Monotonically increasing timestamp on rcvd dgram */
#ifndef __APPLE__
#define SO_ACCEPTFILTER 0x1000          /* there is an accept filter */
#else
#define SO_DONTTRUNC    0x2000          /* APPLE: Retain unread data */
                                        /*  (ATOMIC proto) */
#define SO_WANTMORE     0x4000          /* APPLE: Give hint when more data ready */
#define SO_WANTOOBFLAG  0x8000          /* APPLE: Want OOB in MSG_FLAG on receive */