1. 相关概念
1.1 IP
-
唯一标识Internet上的计算机
-
分类方式1:IPV4和IPV6
- IPV4:4个字节组成,4个0~255,中间用小数点隔开,如192.168.0.1
- IPV6:128位(16个字节)组成,8组无符号整数,中间用冒号隔开,如3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
-
分类方式2:公网地址(万维网)和私网地址(局域网),192.168.开头的就是私有地址
-
在Java中对应的类是InetAddress
-
本地地址:127.0.0.1对应域名是localhost
1.2 端口
-
标识计算机运行的进程
-
不同的进程有不同的端口号
-
端口号是一个16位的整数,范围0~65535
-
分类如下
-
公认端口:0~1023,被预先定义的服务通信占用。如HTTP占用80,FTP占用21
-
注册端口:1024~49151,分配给用户进程或应用程序。如Tomcat占用8080,MySQL占用3306,Oracle占用1521
-
动态/私有端口:49152~65535
-
-
端口号与IP地址组合成一个网络套接字:Socket
1.3 网络协议
网络协议即网络通信中的一些约定。传输层的两个重要协议:TCP和UDP
1.3.1 TCP
- 使用TCP协议前,需建立TCP连接,形成数据传输通道
- 传输前,要进行"三次握手";传输完毕后,要进行"四次挥手"
- TCP的两个应用进程:客户端、服务端
- 连接中可以进行大量数据的传输
- 传输完成需要释放连接,效率低
1.3.2 UDP
- 不建立连接
- 每个数据报限制在64K内
- 只管发送,不管对方是否接收到
- 可以广播发送
- 发送结束不释放资源,速度快
2. TCP和UDP编程
2.1 TCP
2.1.1 例题1
需求:客户端向服务端发送数据,服务端打印到控制台上
public class TCPTest {
@Test
public void client() {
Socket socket = null;
OutputStream os = null;
try {
InetAddress inet = InetAddress.getByName("127.0.0.1");
// 创建Socket对象,指名服务器的ip和端口
socket = new Socket(inet, 8888);
// 获取输出流,用于向服务器输出数据
os = socket.getOutputStream();
os.write("我是客户端".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != os) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != socket) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void server() {
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
// 创建服务器的ServerSocket对象,指名自身的端口
serverSocket = new ServerSocket(8888);
// 调用accept()方法接收客户端的socket
socket = serverSocket.accept();
// 获取socket的输入流
is = socket.getInputStream();
baos = new ByteArrayOutputStream();
byte[] buff = new byte[20];
int len;
while (-1 != (len = is.read(buff))) {
baos.write(buff, 0, len);
}
System.out.println(baos.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != baos) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != is) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != socket) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != serverSocket) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2.1.2 例题2
需求:客户端向服务端发送文件,服务端把文件保存在硬盘上
public class TCPTest2 {
@Test
public void client() throws IOException {
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 8888);
OutputStream os = socket.getOutputStream();
FileInputStream fis = new FileInputStream("E:\\JavaTest\\client\\01.jpg");
byte[] buff = new byte[1024];
int len;
while (-1 != (len = fis.read(buff))) {
os.write(buff, 0 , len);
}
// 这里偷懒直接把异常抛出,正常开发应该用try-catch-finally
fis.close();
os.close();
socket.close();
}
@Test
public void server() throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("E:\\JavaTest\\server\\01.jpg");
byte[] buff = new byte[1024];
int len;
while (-1 != (len = is.read(buff))) {
fos.write(buff, 0, len);
}
fos.close();
is.close();
socket.close();
serverSocket.close();
}
}
2.1.3 例题3
需求:在例题2的基础上,服务端反馈"接收完成"给客户端
public class TCPTest3 {
@Test
public void client() throws IOException {
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 8888);
OutputStream os = socket.getOutputStream();
FileInputStream fis = new FileInputStream("E:\\JavaTest\\client\\01.jpg");
byte[] buff = new byte[1024];
int len;
while (-1 != (len = fis.read(buff))) {
os.write(buff, 0 , len);
}
// 不调用该方法会导致阻塞
socket.shutdownOutput();
// 接收服务端的数据
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
char[] buff2 = new char[10];
StringBuilder sb = new StringBuilder(100);
int len2;
while (-1 != (len2 = isr.read(buff2))) {
sb.append(buff2, 0, len2);
}
System.out.println(sb.toString());
isr.close();
is.close();
fis.close();
os.close();
socket.close();
}
@Test
public void server() throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("E:\\JavaTest\\server\\01.jpg");
byte[] buff = new byte[1024];
int len;
while (-1 != (len = is.read(buff))) {
fos.write(buff, 0, len);
}
OutputStream os = socket.getOutputStream();
os.write("接收完成".getBytes());
os.close();
fos.close();
is.close();
socket.close();
serverSocket.close();
}
}
2.2 UDP
public class UDPTest {
@Test
public void sender() throws Exception {
DatagramSocket socket = new DatagramSocket();
byte[] data = "UDP传输".getBytes();
InetAddress inet = InetAddress.getByName("127.0.0.1");
DatagramPacket packet = new DatagramPacket(data, 0, data.length, inet, 8888);
socket.send(packet);
socket.close();
}
@Test
public void receiver() throws Exception {
DatagramSocket socket = new DatagramSocket(8888);
byte[] buff = new byte[1024];
DatagramPacket packet = new DatagramPacket(buff, 0, buff.length);
socket.receive(packet);
System.out.println(new String(packet.getData(), 0, packet.getLength()));
}
}