互联网通信是套接字进行通信的,套接字,是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。
非常非常简单的举例说明下:套接字=Ip address+ TCP/UDP + port。
java 针对TCP 和 UDP进行了分别的开发封装: Socket,DatagramSocket (早期 JAVA开发者没有开发,DatagramSocket,TCP和UDP都是使用socket的进行开发的,后期加上了DatagramSocket后就把socket中开发UDP的API 废弃了,
现在我们通常说socket开发tcp,DatagramSocket开发UDP)我们通常使用的互联网开发都是tcp,http 建立在tcp之上的协议,即:一个请求一个响应,请求与响应
本质都是socket。也就是说socket与socket之间的通信,通信完毕就会结束链接,即无状态的链接,即这次连接和下次连接都是独立的交互。
请求与响应是一一对应的,不会出现A的响应给了B的请求,因为socket通信是靠四元组进行对接通信的
socket: 四元组 本地IP,本地Port,目标IP,目标Port
serversocket:本质也是socket,为了开发服务器这一角色,所以将socket封装成了serversocket,创建serversocket的时候底层会创建一个socket,然后
会绑定这个socket,同时监听这个socket的端口号并且会提前创建一个用于响应的socket。这样就会做到其他的socket请求该serversocket中的socket,那么监听器就会监听到并触发创建一个新的socket与请求socket进行通信,并且重新监听(扩展:如果还没有来的及从新监听,就在这时,突然有大量的请求过来,那么此时服务器很有可能会崩溃也有你可能拒绝你的请求,此时就出现了消息中间件,比如kafka,activeMQ 等即,让请求消息先来我这里排队,拍好队形在一个一个的去请求,这样就不会突然出现高并发了,放在服务器受不了,最后一个简单的案例说明。 )。并且会提前创建一个socket,等待请求。
源码:
public Socket accept() throws IOException {
if (isClosed())
throw new SocketException("Socket is closed");
if (!isBound())
throw new SocketException("Socket is not bound yet");
Socket s = new Socket((SocketImpl) null); //提前创建好socket 响应
implAccept(s); //当没有请求时线程会停在这里,等待请求
return s;
}
当客户端创建请求socket时,Socket socket = new Socket("localhost",6472); 当请求socket链接到服务器时,socket才算创建成功,否者创建socket失败并会
报错:Exception in thread "main" java.net.ConnectException: Connection refused: connect
当请求socket创建成功后: 四元组 本地IP,本地Port,目标IP,目标Port 都会初始化完成,
本地IP(假设为172.168.17.9),本地Port(java底层会随机给一个未占用的port,假设为2635)
目标IP(服务器的IP,假设为192.168.17.88),目标Port(服务器的端口 假设为 8080)
此时accept()收到请求并且针对当前请求的socket返回一个响应socket,并且该响应socket的四元组 本地IP,本地Port,目标IP,目标Port
都会初始化完成,
本地IP(服务器当前的IP:192.168.17.88),本地Port(java底层会随机给一个未占用的port,假设为1526),
目标IP(请求的IP:172.168.17.9)目标Port(请求的端口:2635 )
此时,请求与响应才会做到了准备无误的对应。才不会出现请求与响应的错乱。
demo:
package com.jvm.others.socket_;
import java.net.Socket;
public class Demo2Soket { //客户端
public static void main(String[] args) throws Exception {
Socket socket = new Socket("localhost",6478);
String hostAddress = socket.getLocalAddress().getHostAddress();
int localPort = socket.getLocalPort();
SocketUtiles.pringHostAndPort(socket);
}
}
客户端打印结果:
Local socket Host : 127.0.0.1
Local socket HostAddress : 127.0.0.1
Local socket Port : 60737
des socket Host : localhost
des socket HostAddress : 127.0.0.1
des socket Port : 6478
当前请求时间 15 5944
package com.jvm.others.socket_;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
public class Demo2ServerSocket { //服务器
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(6478);
while(true){
Socket accept = ss.accept();
SocketUtiles.pringHostAndPort(accept);
}
}
}
服务器打印方式:
Local socket Host : 127.0.0.1
Local socket HostAddress : 127.0.0.1
Local socket Port : 6478
des socket Host : 127.0.0.1
des socket HostAddress : 127.0.0.1
des socket Port : 60737
当前请求时间 15 5944
扩展代码
并发案例服务器受不了拒绝了你:
package com.jvm.others.socket_;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
//模拟客户端请求
public class DemoSocket {
public static void main(String[] args) throws Exception {
for(int i = 0;i<1000;i++){
Socket socket = new Socket("localhost",6466);
String hostAddress = socket.getLocalAddress().getHostAddress();
int localPort = socket.getLocalPort();
SocketUtiles.pringHostAndPort(socket);
}
}
}
package com.jvm.others.socket_;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
//模拟服务器
public class DemoSocketServer {
static int i= 1;
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(6466);
while(true){
Socket accept = ss.accept();
if(i==1){
Date date = new Date();
System.out.println("开始睡觉 当前时间为 : "+date.getHours()+" "+date.getMinutes()+" "+date.getSeconds());
Thread.sleep(4000); //模拟来不及监听,停了4秒
Date date2 = new Date();
System.out.println("睡觉结束 当前时间为 : "+date2.getHours()+" "+date2.getMinutes()+" "+date.getSeconds());
}
i++;
SocketUtiles.pringHostAndPort(accept);
}
}
}
//工具类
package com.jvm.others.socket_;
import java.net.Socket;
import java.util.Date;
public class SocketUtiles {
public static void pringHostAndPort(Socket s){
Date date = new Date();
System.out.println(" Local socket Host : "+s.getLocalAddress().getHostName());
System.out.println(" Local socket HostAddress : "+ s.getLocalAddress().getHostAddress());
System.out.println(" Local socket Port : "+s.getLocalPort());
System.out.println(" des socket Host : "+s.getInetAddress().getHostName());
System.out.println(" des socket HostAddress : "+ s.getInetAddress().getHostAddress());
System.out.println(" des socket Port : "+s.getPort());
System.out.println("当前请求时间 "+date.getHours()+" "+date.getMinutes()+date.getSeconds());
}
}
请求客户端会报Exception in thread "main" java.net.ConnectException: Connection refused: connect 拒绝链接。