网络编程中两个主要问题

  • 如何准确的定位网络上一台或者多台主机:定位主机上特定的应用
  • 找到主机后如何高效可靠的进行信息传输

网络编程中的两个要素

  • IP和端口号
  • 提供网络通信协议:TCP/IP参考模型(应用层、传输层、网络层、物理+数据链路)

InetAddress 类的使用

  • InetAddress.getLocalHost(); 获取本机IP地址
  • InetAddress.getByName("baidu.com"); 根据域名解析对应的IP地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.songzx.javahttp;


import java.net.InetAddress;
import java.net.UnknownHostException;

public class InterAddressTest {
public static void main(String[] args) {
InetAddress localHost = null;
try {
// 获取本机的IP地址
localHost = InetAddress.getLocalHost();
System.out.println(localHost); //=> songzhexiang/192.168.60.80

// 根据域名获取对应的ip地址
InetAddress byName = InetAddress.getByName("baidu.com");
System.out.println(byName); //=> baidu.com/220.181.38.251
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}

TCP和UDP

  • TCP协议
    • 使用TCP协议前,需要建立TCP链接,形成传输数据通道
    • 传输前,采用三次握手方式,点对点进行通信,是可靠的
    • TCP协议进行通信的两个应用进程:客户端、服务端
    • 在链接中可进行大数据量的传输
    • 传出完毕,需要释放已建立的链接,四次挥手,效率低
  • UDP协议
    • 将数据、源封装成数据包,不需要建立链接
    • 每个数据的大小限制在 64K内
    • 发送方不管对方是否准备好,接收方收到后也不会确认,故是不可靠的
    • 可以发送广播
    • 发送数据结束时不需要释放,开销小,速度快

TCP 网络编程1-发送消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package com.songzx.javahttp;

import org.junit.Test;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpTest {
/**
* 客户端方法
* @author Songzx
* @date 2022/1/12
*/
@Test
public void customerVoid(){
Socket socket = null;
OutputStream os = null;
try {
// 1.指明要连接的IP
InetAddress ip = InetAddress.getByName("127.0.0.1");
// 2.创建socket对象,指明ip和端口号
socket = new Socket(ip, 8899);
// 3.创建写入流
os = socket.getOutputStream();
// 4.写数据
os.write("我来自服务端数据".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 5.关闭流
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}


/**
* 服务器方法
* @author Songzx
* @date 2022/1/12
*/
@Test
public void serverVoid(){
ServerSocket socket = null;
Socket accept = null;
InputStream is = null;
ByteArrayOutputStream bos = null;
try {
// 1.创建服务器端的ServerSocket,指明自己的端口号
socket = new ServerSocket(8899);
// 2.接收来自客户端的socket
accept = socket.accept();
// 3.获取客户端的输入流
is = accept.getInputStream();
// 4.读取输入流中的数据
bos = new ByteArrayOutputStream();
// 5.读取数据保存在bos中
int len;
byte[] bytes = new byte[1024];
while ((len = is.read(bytes)) != -1){
bos.write(bytes,0,len);
}
// 6.输出客户端传递过来的数据
System.out.println(bos.toString());
System.out.println("信息来自于" + socket.getInetAddress().getHostAddress());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 7.关闭流
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
accept.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}
}

TCP网络编程2-发送文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.songzx.javahttp;

import org.junit.Test;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
* 实现客户端发送文件,服务端接收并保存
* @author Songzx
* @date 2022/1/12
*/

public class TcpTest2 {
@Test
public void customerVoid() throws IOException{
// 1.指定ip
InetAddress ip = InetAddress.getByName("127.0.0.1");
// 2.链接后台ip和端口
Socket socket = new Socket(ip,8899);
// 3.创建数据写入流
OutputStream os = socket.getOutputStream();
// 4.创建文件读取流读取文件
FileInputStream fis = new FileInputStream("8546859.jpg");
// 5.文件写入操作
int len;
byte[] bytes = new byte[1024];
while ((len = fis.read(bytes)) != -1){
os.write(bytes,0,len);
}
// 6.关闭流
fis.close();
os.close();
socket.close();
}



@Test
public void serverVoid() throws IOException {
// 1.创建端口
ServerSocket socket = new ServerSocket(8899);
// 2.接收客户端信息
Socket accept = socket.accept();
// 3.创建数据读取流
InputStream is = accept.getInputStream();
// 4.创建文件写入流
FileOutputStream fos = new FileOutputStream("save1.png");
// 5.文件写入操作
int len;
byte[] bytes = new byte[1024];
while ((len = is.read(bytes)) != -1){
fos.write(bytes,0,len);
}
// 6.关闭流
fos.close();
is.close();
accept.close();
socket.close();
}
}

TCP网络编程3-客户端接收服务端消息

客户端发送完毕数据后,要显示的调用一下关闭方法来告诉服务端数据发送完毕,避免服务端一直读取数据造成进程阻塞

  • socket.shutdownOutput();
  • socket.shutdownInput();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package com.songzx.javahttp;

import org.junit.Test;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
* 实现客户端发送文件,服务端接收并保存
* @author Songzx
* @date 2022/1/12
*/

public class TcpTest2 {
@Test
public void customerVoid() throws IOException{
// 1.指定ip
InetAddress ip = InetAddress.getByName("127.0.0.1");
// 2.链接后台ip和端口
Socket socket = new Socket(ip,8899);
// 3.创建数据写入流
OutputStream os = socket.getOutputStream();
// 4.创建文件读取流读取文件
FileInputStream fis = new FileInputStream("8546859.jpg");
// 5.文件写入操作
int len;
byte[] bytes = new byte[1024];
while ((len = fis.read(bytes)) != -1){
os.write(bytes,0,len);
}
// 图片传输完毕后要明确的告诉服务端数据传输完成,否则服务端会一直接收数据,流程进入阻塞状态不会往下执行
socket.shutdownOutput();


// 6.接收服务端返回的消息
InputStream is = socket.getInputStream();
int len1;
byte[] bytes1 = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((len1 = is.read(bytes1)) != -1){
baos.write(bytes1,0,len1);
}
System.out.println(baos.toString()); //=> 我已收到,很漂亮

// 7.关闭流
fis.close();
os.close();
socket.close();
is.close();
baos.close();
}



@Test
public void serverVoid() throws IOException {
// 1.创建端口
ServerSocket socket = new ServerSocket(8899);
// 2.接收客户端信息
Socket accept = socket.accept();
// 3.创建数据读取流
InputStream is = accept.getInputStream();
// 4.创建文件写入流
FileOutputStream fos = new FileOutputStream("save1.png");
// 5.文件写入操作
int len;
byte[] bytes = new byte[1024];
while ((len = is.read(bytes)) != -1){
fos.write(bytes,0,len);
}
// 6.给客户端回复消息
OutputStream os = accept.getOutputStream();
os.write("我已收到,很漂亮".getBytes());
// 7.关闭流
fos.close();
is.close();
accept.close();
socket.close();
os.close();
}
}

UDP网络编程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.songzx.javahttp;

import org.junit.Test;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UdpTest {
/**
* 发送数据方法
* @author Songzx
* @date 2022/1/13
*/
@Test
public void sendVoid() throws IOException {
// 创建DatagramSocket类实例
DatagramSocket dgs = new DatagramSocket();
// 声明要发送的数据
String sendStr = "我是通过udp发送的数据";
byte[] bytes = sendStr.getBytes();
// 指明要发送的地址
InetAddress host = InetAddress.getByName("127.0.0.1");
// 指明端口号
int prop = 8899;
// 封装数据包
DatagramPacket dp = new DatagramPacket(bytes, 0, bytes.length, host,prop);
// 发送数据
dgs.send(dp);
// 关闭流
dgs.close();
}

/**
* 接收数据方法
* @author Songzx
* @date 2022/1/13
*/
@Test
public void receiveVoid() throws IOException{
// 创建数据源的同时指定端口号
DatagramSocket dgs = new DatagramSocket(8899);
// 创建一个存放数据的容器
byte[] bytes = new byte[1024];
// 创建数据包
DatagramPacket dp = new DatagramPacket(bytes, 0, bytes.length);
// 接收数据
dgs.receive(dp);
// 输出数据
System.out.println(new String(dp.getData(), 0, dp.getLength()));
// 关闭流
dgs.close();
}
}

URL 类常用的方法

url:统一资源定位符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.songzx.javahttp;

import java.net.MalformedURLException;
import java.net.URL;

public class UrlTest {
public static void main(String[] args) {
try {
URL url = new URL("http://baidu.com:8080?className=123");
// 获取协议
System.out.println(url.getProtocol()); //=> http
// 获取域名和端口
System.out.println(url.getAuthority()); //=> baidu.com:8080
// 获取端口
System.out.println(url.getPort()); //=> 8080
// 获取查询参数
System.out.println(url.getQuery()); //=> className=123
// 获取域名
System.out.println(url.getHost()); //=> baidu.com
} catch (MalformedURLException e) {
e.printStackTrace();
}

}
}