背景:公司在线客服老代码多线程数据安全问题严重,以及层级之间互相调用,导致了严重的耦合。对项目进行相应的重构。
- 什么是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 */