小白的成长来源于努力学习,坚持每天的积累。 ——半杯态
计算机之间的通信,依据于TCP/IP协议簇中的传输层,它分为两种一种是TCP(传输控制协议)和IP(网际协议)。在Java中用Class为ServerSocket
类和Socket
代表用TCP传输形式,使用DatagramSocket代表使用UDP进行传输。
Socket(也可以叫“套接字”),是两台机器间通信的端点。可以和网卡驱动进行交流。负责把数据交给网卡驱动,或者从网卡驱动中提取数据。
实现网络之间通信分为两种传输方式:TCP,UDP
TCP (可靠,数据流,面向连接)
分客户端(client),服务端(server)两个角色
情景一:实现简单版单机通信方式
提示:可以结合TCP/IP三次握手进行理解
客户端实现:
package com.banbeitai.io.socket.communication;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
/*
* TCP:
* 客户端,主动连接服务器
*
* Socket(InetAddress address, int port)
* Socket(String host, int port)
*
* 步骤:
* 1、连接服务器
* Socket socket = new Socket("192.168.30.2",9999);
*
* 2、发送或接受数据
*
* 3、断开连接
*/
public class TestClientVersion1 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 9999);
byte[] data = new byte[1024];
InputStream inputStream = socket.getInputStream();
int len;
if ((len=inputStream.read(data))!=-1){
System.out.println(new String(data,0,len));
}
}
}
服务端实现:
package com.banbeitai.io.socket.communication;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TestServerVersion1 {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9999);
Socket socket = server.accept();
System.out.println(socket.getInetAddress() + "客户端连接成功!");
OutputStream outputStream = socket.getOutputStream();
outputStream.write("欢迎你登录成功".getBytes());
socket.close();
server.close();java
}
}
根据图以及代码可知:
第一步:客户端发送请求到服务端,告知服务端,客户端发送请求是可以的。
第二步:
Socket socket = server.accept();
这行代码表示服务端进行接收,getOutputStream
方法代表是发送,相当于SYN+ACK,代表服务端,接收和发送第三步:就是客户端接收到服务端的发送的信息,响应可以成功接收指令给服务端
由此可以建立两个设备间的通信。
情景二:实现短连接的通信
短连接:建立网络通信,两个服务或者设备之间每次都要进行建立连接,造成很大开销,这是HTTP1.0
客户端实现:
package com.banbeitai.io.socket.communication;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* 客户单发送请求,并响应服务端的请求
*/
public class TestClientVersion2 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 9999);
OutputStream outputStream = socket.getOutputStream();
//第一次握手,由客户端进行发送 SYN 目的是确定客户端能够发送消息
outputStream.write("你好,服务端,我是半杯态".getBytes());
/**
* out.close();//错误的,如果调用out.close()会导致socket的close()
* 状态处于半开状态,只关闭了输出的通道
* 调用此方法为了,暂时关闭客户端,如果不关闭,服务端是以为还有消息发送,不会给出响应,处于等待状态
*/
socket.shutdownOutput();
//第三次握手,接受到消息并响应,建立网络通信 ACK 目的是告诉客户端可以收到服务端的消息
System.out.println("客户端收到:");
InputStream in = socket.getInputStream();
byte[] data = new byte[1024];
int len;
while((len = in.read(data)) != -1){
System.out.println(new String(data,0,len));
}
socket.close();
}
}
服务端实现:
package com.banbeitai.io.socket.communication;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务端接收客户端的消息,并返回给客户端一个回复,代表链接成功
* 可以理解为短连接
*/
public class TestServerVersion2 {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9999);
//第二次握手,服务端接受并发送 SYN+ACK 目的是为响应客户端,服务端可以收到信息,并且可以发送消息
Socket socket = server.accept();
System.out.println(socket.getInetAddress()+"客户端连接成功");
InputStream in = socket.getInputStream();
byte[] data = new byte[1024];
int len;
System.out.println("服务器收到:");
while ((len = in.read(data)) != -1) {
System.out.println(new String(data,0,len));
}
OutputStream outputStream = socket.getOutputStream();
outputStream.write("欢迎你,半杯态,你登录成功".getBytes());
socket.close();
server.close();
}
}
情景三:实现长连接的通信
长连接:建立网络通信,两个服务或者设备之间可以持续的进行交互,这是HTTP1.1
客户端实现:
package com.banbeitai.io.socket.communication;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class TestClientVersion3 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 9999);
OutputStream outputStream = socket.getOutputStream();
PrintStream printStream = new PrintStream(outputStream);
Scanner input = new Scanner(System.in);
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
System.out.println("请输入词语:");
String word = input.next();
//发送给服务器端
printStream.println(word);
if ("bye".equalsIgnoreCase(word)) {
break;
}
String result = br.readLine();
System.out.println("服务器转换后的数据:"+ result);
}
input.close();
socket.close();
}
}
服务端实现:
package com.banbeitai.io.socket.communication;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TestServerVersion3 {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9999);
Socket socket = server.accept();
InputStream inputStream = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
PrintStream ps = new PrintStream(socket.getOutputStream());
String word;
while ((word = br.readLine()) != null) {
if ("bye".equalsIgnoreCase(word)) {
break;
}
StringBuilder sb = new StringBuilder(word);
sb.reverse();
ps.println(sb.toString());
}
socket.close();
server.close();
}
}
UDP(不可靠,数据报文,无连接)
分发送端(Send),接收端(Receive)两个角色
Class DatagramSocket 常用方法:
方法 | 返回值 | 含义 |
---|---|---|
DatagramSocket() | 无 | 构建一个数据报套接字绑定到本地主机的任何可用的端口, |
DatagramSocket(int port) | 无 | 构建一个数据报套接字绑定到本地主机的指定端口, |
connect(InetAddress address, int port) | void | 将套接字连接到这个套接字的远程地址。 |
send(DatagramPacket p) | void | 从这个套接字发送数据报包。 |
DatagramPacket 常用方法:
方法 | 返回值 | 含义 |
---|---|---|
DatagramPacket(byte[] buf, int length) | 无 | 无接收数据包长度 length DatagramPacket构建 |
getData() | byte[] | 返回数据缓冲区。数据的接收或发送的数据从缓冲区中的 offset,和运行 length长。 |
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) | 无 | 发送有偏置 ioffsetto指定端口号指定主机上的数据包长度 length数据报包结构。 |
发送端:
package com.banbeitai.io.socket.udp;
import java.io.IOException;
import java.net.*;
public class TestSend {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
//2、准备把要发送的数据打包
String str = "欢迎半杯态";
byte[] bytes = str.getBytes();
InetAddress ip = InetAddress.getByName("127.0.0.1");
DatagramPacket dp = new DatagramPacket(bytes,0,bytes.length, ip, 9999);
ds.send(dp);
System.out.println("发送完毕");
ds.close();
}
}
接收端:
package com.banbeitai.io.socket.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class TestReceive {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(9999);
//2、准备一个数据报,接收数据
byte[] data = new byte[1024];
DatagramPacket dp = new DatagramPacket(data,data.length);
ds.receive(dp);
byte[] dpData = dp.getData();
// int len = dp.getLength();
System.out.println(new String(dpData,0,dp.getLength()));
ds.close();
}
}