1、socket
在OSI七层网络模型中,Socke接口处于OSI 七层模型的表示层,利用socket接口编程的代码处于应用层
Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议
2、linux和windows中的socket
2.1、unix/linux中的socket
unix/linux中的一切都是文件
在 UNIX/Linux 系统中,为了统一对各种硬件的操作,简化接口,不同的硬件设备也都被看成一个文件。对这些文件的操作,等同于对磁盘上普通文件的操作
为了表示和区分已经打开的文件,UNIX/Linux 会给每个文件分配一个 ID,这个 ID 就是一个整数,被称为文件描述符(File Descriptor)。例如:
通常用 0 来表示标准输入文件(stdin),它对应的硬件设备就是键盘;
通常用 1 来表示标准输出文件(stdout),它对应的硬件设备就是显示器。
UNIX/Linux 程序在执行任何形式的 I/O 操作时,都是在读取或者写入一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数,它的背后可能是一个硬盘上的普通文件、FIFO、管道、终端、键盘、显示器,甚至是一个网络连接。
请注意,网络连接也是一个文件,它也有文件描述符!
通过 socket() 函数可与来创建一个网络连接,或者说打开一个网络文件,socket() 的返回值就是文件描述符。有了文件描述符,我们就可以使用普通的文件操作函数来传输数据了,例如:
用 read() 读取从远程计算机传来的数据;
用 write() 向远程计算机写入数据。
只要用 socket() 创建了连接,剩下的就是文件操作了
2.2、windows中的socket
Windows 也有类似“文件描述符”的概念,但通常被称为“文件句柄”
与 UNIX/Linux 不同的是,Windows 会区分 socket 和文件,Windows 就把 socket 当做一个网络连接来对待,因此需要调用专门针对 socket 而设计的数据传输函数,针对普通文件的输入输出函数就无效了
3、套接字分类
流格式套接字(SOCK_STREAM)也叫面向连接的套接字,基于TCP
数据报格式套接字(SOCK_DGRAM)也叫“无连接的套接字”,基于UDP
QQ 视频聊天和语音聊天就使用 SOCK_DGRAM 来传输数据,因为首先要保证通信的效率,尽量减小延迟,而数据的正确性是次要的,即使丢失很小的一部分数据,视频和音频也可以正常解析,最多出现噪点或杂音,不会对通信质量有实质的影响。
注意:SOCK_DGRAM 没有想象中的糟糕,不会频繁的丢失数据,数据错误只是小概率事件
4、MAC地址
现实的情况是,一个局域网往往才能拥有一个独立的 IP;换句话说,IP 地址只能定位到一个局域网,无法定位到具体的一台计算机。这可怎么办呀?这样也没法通信啊。
其实,真正能唯一标识一台计算机的是 MAC 地址,每个网卡的 MAC 地址在全世界都是独一无二的。计算机出厂时,MAC 地址已经被写死到网卡里面了(当然通过某些“奇巧淫技”也是可以修改的)。局域网中的路由器/交换机会记录每台计算机的 MAC 地址
MAC 地址是 Media Access Control Address 的缩写,直译为“媒体访问控制地址”,也称为局域网地址(LAN Address),以太网地址(Ethernet Address)或物理地址(Physical Address)。
数据包中除了会附带对方的 IP 地址,还会附带对方的 MAC 地址,当数据包达到局域网以后,路由器/交换机会根据数据包中的 MAC 地址找到对应的计算机,然后把数据包转交给它,这样就完成了数据的传递
5、redis通信协议
redis 客户端和服务端之间通信的协议是RESP(REdis Serialization Protocol)。传输层使用TCP。RESP的特点是:
- 实现容易
- 解析快
- 人类可读
5.1、请求格式
*3\r\n
$3\r\n
set\r\n
$4\r\n
name\r\n
$8\r\n
zhangsan\r\n
5.2、响应格式
对于简单字符串,回复的第一个字节是“+”
对于错误,回复的第一个字节是“ - ”
对于整数,回复的第一个字节是“:”
对于批量字符串,回复的第一个字节是“$”
对于数组,回复的第一个字节是“ *”
5.3、代码样例
public class RedisSocket {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 6379);
new Thread(new Runnable() {
@Override
public void run() {
try {
InputStream in = socket.getInputStream();
int len = 0;
byte[] b = new byte[1024];
while((len = in.read(b)) != -1){
System.out.println(new String(b,0,len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
OutputStream out = socket.getOutputStream();
String cmd = "*3\r\n$3\r\nset\r\n$4\r\nbobo\r\n$3\r\nlzz\r\n";
out.write(cmd.getBytes());
out.flush();
System.in.read();
}
}