1、 Socket的工作流程
Socket实质上提供了进程通信的端点。进程通信之前,双方首先必须各自创建一个端点,否则是没有办法建立联系并相互通信的。正如打电话之前,双方必须各自拥有一台电话机一样。
对于一个功能齐全的Socket,都要包含以下结构,其工作流程包含以下四个基本步骤:
(1) 创建Socket
(2) 打开连接到Socket的输入/输出流
(3) 按照一定的协议对Socket进行读/写操作
(4) 关闭Socket
2、 java中的Socket
java中的socket通信主要通过两个已经封装好的类ServerSocket和Socket
socket通常开发的是客户端,用来让客户端通过端口号和IP地址连接到远程服务器。而ServerSocket实现的则是一个服务器应用,ServerSocket会一直等待客户端的请求,一旦获得了一个连接请求,就创建一个socket示例来与客户端进行通信。ServerSocket会绑定一个固定的端口,知晓此端口和远程服务器的客服端可以通过IP地址和端口号来与远程客户端通信,而服务端的端口则是随机的,在socket的应用中,我们并不关心客户端的端口号。
3、 实现
Java中的socket在底层实现时最终是通过调用系统的socket来实现的,下面是java中的socket类的继承关系
从上图中可以看出ServerSocket就是针对SocketImpl的一个外观类。SocketImple是一个抽象类,并且这个抽象类SocketImpl实现了SocketOptions接口。
SocketOptions接口中声明的final属性
SocketImpl中的属性
4、 windows和Linux中的socket
windows在windows中socket方法返回的是SOCKET 一个宏定义
如下图所示
从上方代码看出他是u_int类型的别名,一个文件描述符为什么是int呢?因为在windows编程下主要使用的是句柄,而句柄就是一串int数字这个数字标识这一个内存中的类(这里可以理解在系统中是键值对而这个int则是key,而他获取的对象则就是我们使用accept或bind所需要的),暂时可以这么理解因为即使是内存也是键值对的map,各位读者暂时将这个int当做一个key值而调用其他socket方法都是需要这个key值的没有这个key是操作不了的。
linux在linux中socket方法比windows要直接,他直接返回的是int类型
如下图所示
上面都是针对linux和windows的讲解那么在java中是怎么描述的呢?
上面的代码是从SocketImpl中的bind方法的jni实现中的,可以看出他先获取了FileDescriptor对象也就是SocketImpl的fd,然后再根据FileDescriptor获取到他的fd我们最终使用的文件描述符,而文件描述符也是int类型的,所以在java中的socket方法返回的也是int类型。
5、java中的socket和Linux的socket的区别
Socket是winsock里的原始套接字开发接口API,java是一门开发语言,而socket是一种通讯标准的简称。Linux中的socket指的就是系统底层的socket,而像java这些开发语言,因为java本身是不带有socket通讯底层实现的,所以他们所使用的socket只不过是对系统底层的Socket API进行了二次封装,面向开发人员,其本质上仍然和Linux底层的socket是同一个东西
6、java中的Socket用法
(1) Socket的构造
Socket() 通过系统默认类型的 SocketImpl 创建未连接套接字
Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
Socket(String host, int port)
Socket(String host, int port, InetAddress localAddr, int localPort) 创建一个套接字并将其连接到指定远程主机上的指定远程端口。
(2) 方法摘要
void |
bind(SocketAddress bindpoint)
|
void |
close() |
void |
connect(SocketAddress endpoint)
|
void |
connect(SocketAddress endpoint,
int timeout) |
getChannel() |
|
getInetAddress() |
|
getInputStream() |
|
boolean |
getKeepAlive() |
getLocalAddress() |
|
int |
getLocalPort() |
getLocalSocketAddress() |
|
boolean |
getOOBInline() |
getOutputStream() |
|
int |
getPort() |
int |
getReceiveBufferSize() |
getRemoteSocketAddress() |
|
boolean |
getReuseAddress() |
int |
getSendBufferSize() |
int |
getSoLinger() |
int |
getSoTimeout() |
boolean |
getTcpNoDelay() |
int |
getTrafficClass() |
boolean |
isBound() |
boolean |
isClosed() |
boolean |
isConnected() |
boolean |
isInputShutdown() |
boolean |
isOutputShutdown() |
void |
sendUrgentData(int data) |
void |
setKeepAlive(boolean on) |
void |
setOOBInline(boolean on) |
void |
setPerformancePreferences(int connectionTime,
int latency, int bandwidth) |
void |
setReceiveBufferSize(int size) |
void |
setReuseAddress(boolean on) |
void |
setSendBufferSize(int size) |
static void |
setSocketImplFactory(SocketImplFactory fac)
|
void |
setSoLinger(boolean on,
int linger) |
void |
setSoTimeout(int timeout) |
void |
setTcpNoDelay(boolean on) |
void |
setTrafficClass(int tc) |
void |
shutdownInput() |
void |
shutdownOutput() |
7、javasocket编程-简单的hello/hi实现
基于服务器端实现的一个简单的聊天机器人,可支持多人同时聊天
效果如下:
左边的是聊天服务器,右边两个是客户端
聊天恢复,第二个客户端下线
代码实现:
Demo_Receive.java:
Demo_Send.java:
Java中实现多线程主要有两种方法:
1、 继承Thread类,重写run()方法
2、 实现Runnable接口,重写Run()方法
这里使用的是第二种方法
作者:
SA19225475
参考:
https://www.jianshu.com/p/83d5598b9d3b java中socket的实现
https://blog.csdn.net/weixin_34220834/article/details/85747263
JAVA Socket编程和C++ Socket编程有什么不同
https://blog.csdn.net/weixin_33829657/article/details/92413466
JAVA中的socket的继承关系