背景:
- socket是Java为了简化网络协议操作而抽象成几个简单操作(打开—读/写—关闭)的工具类
- TCP和UDP两种传输协议,前者可靠占资源,后者只保证大致连贯。
- socket的协议更加贴合TCP的相关开发,但是也网上也能找到UDP的案例,详情可以参考此https://www.cnblogs.com/zhengtu2015/p/7294477.html
- 如有错误希望指出
1.TCP/IP简单知识简单介绍
下面是从网络上找到的一个TCP/IP协议的四层模型,
初学者可以简单理记忆:快件(应用层)-》中通快递(传输层)-》目的地的地址(网络层)-》快递小哥开始跑腿(链路层)
Java开发一般操作的是应用层和传输层
大名鼎鼎的三次握手建立链接,其过程如下图,在此过程中双发获取到对方的ip:port(用于准确定位目标)。还有一些其它信息。
传输过程如何保证包不丢失?
传输简单过程如下,详细过程可自行百度 tcp传输窗口
1.信息(文本,文件)传输前会被切割成好多份,每份都有一个编号;
2.接收端会有个虚拟的窗口,譬如窗口大小是4,拿他每次最多能接收四份数据;
3.开始的时候,接收端会把需要接收的编号(1.2.3.4)发给源端,源端就发送这四份数据一起发给接收端
4.如果2号数据先到达,窗口不变,继续等待接收,如果这时1号数据到达,三号未到达,窗口往后移两位,同时请求标号5.6份数据…
四次分手就不说了,有兴趣自行百度
2.Java socket
Java Socket(套接字)通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。
两个socket类——Socket,ServerSocket
使用最频繁的几个方法
Accept方法用于产生"阻塞",监听端口直到有终端连接请求,生成一个响应socket实体。
getInputStream方法获得网络连接输入,用bufferedreader等进行解析。
getOutputStream方法连接的另一端将得到输入,输出给终端。
另外还有超时,校验存活的方法
socket的运行流程
两侧都是Java提供的方法,可以看出整个过程中基本上只需要用到上面说到的三个方法即可。
另外,TCP的握手过程是发生在C/S双方生成socket的过程中,并不需要开发人员去实现TCP的复杂过程
例行代码
//服务端
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(25,1); //连接请求等待队列只有1,可以在accept前sleep一下,然后用 telnet 127.0.0.1 25 去连接测试
while (true) {
Socket socket = server.accept();
new Thread(() -> { //这里可以使用线程池去优化,主要看自身业务
System.out.println(socket);
try (InputStream in = socket.getInputStream()) { //获取输入流
System.out.println(socket.getSoTimeout());
// socket.setSoTimeout(10000);
InputStreamReader inputStreamReader = new InputStreamReader(in);
BufferedReader reader = new BufferedReader(inputStreamReader);
OutputStream out = socket.getOutputStream();
// 重点重点,下面也就read,write,read,write...
out.write("220 yyw.cn Esmtp YYW Mail Server\r\n".getBytes());
out.flush();
String s;
while ((s = reader.readLine()) != null) {
System.out.println(s);
s=s.toLowerCase();
if ("quit".equals(s)) {
out.write("220 bye\r\n".getBytes());
out.flush();
break;
}
switch (s) {
case "helo":
out.write("250 OK\r\n".getBytes());
break;
case "auth login" :
out.write("334 MailAccount\r\n".getBytes());
break;
}
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
//客户端
public static void main(String[] args) throws Exception {
Socket socket = new Socket("127.0.0.1", 25);
try (InputStreamReader isr = new InputStreamReader(socket.getInputStream())) {
try (BufferedReader br = new BufferedReader(isr)) {
String a;
int i;
Random r = new Random();
while ((a = br.readLine()) != null && !"220 bye".equals(a)) {
System.out.println(a);
OutputStream os = socket.getOutputStream();
i = r.nextInt(3) + 1;
switch (i) {
case 1:
os.write("helo\r\n".getBytes());
System.out.println("helo");
break;
case 2:
os.write("auth login\r\n".getBytes());
System.out.println("auth login");
break;
default:
os.write("quit\r\n".getBytes());
System.out.println("quit");
}
os.flush();
}
System.out.println(a);
}
} finally {
socket.close();
}
}
参考连接:
https://blog.csdn.net/lvyuan30276/article/details/50458572
https://www.cnblogs.com/mingforyou/p/3258418.html