网络编程
概述
将不同物理设备通过通讯线路连接起来,在网络系统的作用下实现通讯和内容共享。
网络通讯的要素
- 网路编程中的两个问题
- 如何准确定位一台主机或多台主机
- 找到主机之后怎么进行通讯
- 网路编程的要素
- IP + 端口号
- 网络通讯协议

网络编程主要针对--传输层。
IP
java
public class TestInetAddress {
public static void main(String[] args) {
// InetAddress 没有构造方法
try {
InetAddress inetAddress1 = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress1);
//查询本机地址
InetAddress inetAddress2 = InetAddress.getByName("127.0.0.1");
System.out.println(inetAddress2);
InetAddress inetAddress3 = InetAddress.getByName("localhost");
System.out.println(inetAddress3);
//常用方法
System.out.println(inetAddress2.getCanonicalHostName());
System.out.println(inetAddress2.getHostAddress());
System.out.println(inetAddress2.getHostName());
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
}
端口
端口表示一台计算机上的某一个进程。
-
不同进程的端口号不同,端口号用来区分不同的软件!
-
端口的范围:0~65535
-
TCP和UDP的端口号范围都是0~65535;单个协议下端口不能冲突,TCP和UDP在同一台计算机上都拥有80端口这个不会冲突;
-
端口分类:
- 公有端口:0~1023
- HTTP:80
- HTTPS:43
- FTP:21
- Telnet:23
- 程序端口:1024~49151,分配用户或者程序
- Tomcat:8080
- MySQL:3306
- Oracle:1521
- 动态、私有端口:49152~65535
cmdnetstat -ano #查看所有的端口 netstat -ano|findstr "5900" #查看指定的端口 tasklist|findstr "8696" #查看指定端口的进程javapublic class TestInetSocketAddress { public static void main(String[] args) { //根据IP+port获取主机信息 InetSocketAddress inetSocketAddress1 = new InetSocketAddress("127.0.0.1", 8080); InetSocketAddress inetSocketAddress2 = new InetSocketAddress("localhost", 8080); System.out.println(inetSocketAddress1); System.out.println(inetSocketAddress2); System.out.println(inetSocketAddress1.getAddress());//获取地址 System.out.println(inetSocketAddress1.getHostName());//获取主机名 System.out.println(inetSocketAddress1.getPort());//获取端口 } } - 公有端口:0~1023
通讯协议
按照约定的通讯格式(json、xml等格式)、同步方式进行通讯。比如:两个不同地区的人用普通话进行加交流,而不是各自用方言。
TCP/IP协议:是一组协议
三次握手和四次挥手,核心就是:TCP协议像两个礼貌且严谨的人沟通,建立连接时要双向确认,断开连接时也要双向确认,确保没有信息遗漏或误操作。
- 三次握手
java
1.你拨通电话说:"喂,听得到吗?"(第一次握手:客户端发送连接请求)
2.朋友接起电话回答:"听得到,你呢?"(第二次握手:服务端确认收到请求,并也发出连接请求)
3.你接着说:"我也听得到,我们开始聊吧。"(第三次握手:客户端确认服务端的请求)
至此,双方都确认了对方能听清自己,自己也能听清对方,可靠的通话(连接)就建立了。
客户端A和服务端B建立连接时:A先请求B开始建立连接;B收到请求后应答A表示已收到A的请求;A在收到B的请求后再次应答B,表示A在等待B的应答并正式建立通讯。
- 四次挥手
java
四次挥手,就像挂电话结束通话:
1.你说:"我要说的都说完了,我准备挂电话了。"(第一次挥手:客户端发送断开请求)
2.朋友说:"好的,我知道了。"(但朋友可能还有话没说完,所以他先确认收到你的挂断意向,但不立即挂断)(第二次挥手:服务端确认断开请求)
3.朋友把最后几句话说完,然后说:"我也说完了,我也要挂了。"(第三次挥手:服务端发送自己的断开请求)
4.你回答:"好的,再见。"(第四次挥手:客户端确认服务端的断开请求)
至此,双方都确认了对方已无话要说,且都知道通话要结束,才能安心挂断(连接关闭)。
之所以挥手是四次,客户端A在告知服务端B断开连接时,B应答A可以断开(表示B收到A的断开请求);此时B检查自己要传输给A的内容是否完成,完成后通知A断开连接;A在收到B的正式断开通知后,回复B表示内容已全部收到可以断开。
TCP和UDP
TCP--用户传输协议,比如:打电话
- 需要建立连接,才能通讯;
- 相对于UDP传输可靠,效率低;
- 面向字节流,传输的内容可以分开传输,接收后组合起来;
- 适用场景:数据库连接访问、网页浏览、文件传输、远程登录、电子邮件等;
UDP--用户数据报协议,比如:发短信
- 不需要建立连接就能通讯;
- 相对于TCP传输不可靠,效率高;
- 面向数据报,传输内容不能分开,一次传输一数据个报;
- 使用场景:实时音视频、广播等。
TCP
- 服务端
1.建立服务,监听指定的端口
2.等待客户端连接
3.接受客户端消息
java
public class TCPServerDemo01 {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket accept = null;
InputStream is = null;
ByteArrayOutputStream bos = null;
try {
//1.建立服务
serverSocket = new ServerSocket(9999);
//2.等待请求
accept = serverSocket.accept();
//3.接受请求
is = accept.getInputStream();
//建立管道流接收请求
bos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len = is.read(buf)) != -1){
bos.write(buf,0,len);
}
System.out.println(bos.toString());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if(bos != null){
try {
bos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(is != null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(accept != null){
try {
accept.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(serverSocket != null){
try {
serverSocket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
java
//在处理客户端消息时,以下处理会存在问题:如果缓冲区大小1024字节正好截断了一个多字节字符(如UTF-8的中文字符);最后一个字符可能被分割,导致乱码;所以使用"管道流"进行处理
byte[] buf = new byte[1024];
int len = 0;
StringBuffer sb = new StringBuffer();
while((len = is.read(buf)) != -1){
String msg = new String(buf,0,len);
sb.append(msg);
}
System.out.println(sb.toString());
-
客户端
1.连接服务
2.发送消息
java
public class TCPClientDemo01 {
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
try {
//1.获取连接
InetAddress serIp = InetAddress.getByName("127.0.0.1");
int port = 9999;
socket = new Socket(serIp, port);
//2.发送请求
byte[] bytes = "客户端发送测试".getBytes();
os = socket.getOutputStream();
os.write(bytes);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if(os != null){
try {
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(socket != null){
try {
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
使用TCP连接,实现文件传输
客户端:
java
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
FileInputStream fis = null;
InputStream is = null;
ByteArrayOutputStream bos = null;
try {
//1.和服务器建立连接
socket = new Socket(InetAddress.getByName("127.0.0.1"),8888);
//2.读取要上上传的文件
os = socket.getOutputStream();
fis = new FileInputStream(new File("1.png"));
//3.发送给服务端
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf)) != -1){
os.write(buf,0,len);
}
System.out.println("客户端发送文件结束");
socket.shutdownOutput();//表示文件传输完成
is = socket.getInputStream();
bos = new ByteArrayOutputStream();
byte[] buf2 = new byte[1024];
int len2 = 0;
while((len2 = is.read(buf2)) != -1){
bos.write(buf2,0,len2);
}
System.out.println("客户端接收到的返回:"+bos.toString());
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
if(bos != null){
bos.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
if(fis != null){
fis.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
if(os != null){
os.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
if(socket != null){
socket.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
服务端:
java
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
FileOutputStream fos = null;
OutputStream os = null;
try {
//1.启动服务,监听指定端口
serverSocket = new ServerSocket(8888);
System.out.println("服务端监听中。。。");
socket = serverSocket.accept();
//2.读取接收的文件
is = socket.getInputStream();
fos = new FileOutputStream(new File("receive.png"));
byte[] buf = new byte[1024];
int len = 0;
while((len = is.read(buf)) != -1){
fos.write(buf,0,len);
}
System.out.println("服务端文件接收成功");
//发送消息通知客户端文件接收成功
os = socket.getOutputStream();
os.write("服务端接收文件成功,可以断开连接".getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if(os != null){
os.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
if(fos != null){
fos.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
if(is != null){
is.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
if(socket != null){
socket.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
if(serverSocket != null){
serverSocket.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
UDP
代码示例
注意:UDP通讯时,会以包的形式发送和接收信息;在接收消息时需根据实际情况定义接收端的byte大小,防止接收打的消息丢失。
发送端
java
public class UPDClientTest01 {
public static void main(String[] args) {
DatagramSocket socket = null;
try {
//1.建立socket
socket = new DatagramSocket();
//2.创建要发送的包
String reqMsg = "UDP";
InetAddress ip = InetAddress.getByName("127.0.0.1");
int port = 9999;
DatagramPacket sendPacket = new DatagramPacket(reqMsg.getBytes(), 0, reqMsg.getBytes().length, ip, port);
//3.发送
socket.send(sendPacket);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//4.关闭流
if(socket != null){
socket.close();
}
}
}
}
接收端
java
public class UPDReceiveTest01 {
public static void main(String[] args) {
DatagramSocket socket = null;
try {
//1.启动socket监听
socket = new DatagramSocket(9999);
//2.接收包
byte[] buf = new byte[1024];//如果接收到的消息大于这个长度,超出部分会被丢弃,需要根据实际情况进行定义
DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
socket.receive(packet);
System.out.println(packet.getAddress());//发送端的IP
System.out.println(new String(packet.getData(),0, packet.getLength()));//接收到的消息
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//3.关闭连接
if(socket != null){
socket.close();
}
}
}
}
UDP--实现聊天
java
public class UdpSendDemo01 {
public static void main(String[] args) throws Exception{
System.out.println("发送端");
DatagramSocket socket = new DatagramSocket(6666);
while(true){
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String reqMsg = reader.readLine();
DatagramPacket packet = new DatagramPacket(reqMsg.getBytes(), 0, reqMsg.getBytes().length, InetAddress.getByName("127.0.0.1"), 8888);
socket.send(packet);
if(reqMsg.indexOf("bye") != -1){
break;
}
}
socket.close();
}
}
java
public class UdpSendDemo02 {
public static void main(String[] args) throws Exception{
System.out.println("接收端");
DatagramSocket socket = new DatagramSocket(8888);
while(true){
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
socket.receive(packet);
byte[] data = packet.getData();
String reqMsg = new String(data,0, packet.getLength());
System.out.println(reqMsg);
if(reqMsg.indexOf("bye") != -1){
break;
}
}
socket.close();
}
}
UDP--在线聊天
java
public class ChatSend implements Runnable{
private String targetIp;//接收方IP
private int targetPort;//接收方端口
private DatagramSocket socket = null;
public ChatSend(String targetIp,int targetPort) throws IOException{
this.targetIp = targetIp;
this.targetPort = targetPort;
socket = new DatagramSocket();
}
@Override
public void run() {
while(true){
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String reqMsg = reader.readLine();
DatagramPacket packet = new DatagramPacket(reqMsg.getBytes(), 0, reqMsg.getBytes().length, InetAddress.getByName(this.targetIp), this.targetPort);
socket.send(packet);
if(reqMsg.indexOf("bye") != -1){
break;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
socket.close();
}
}
java
public class ChatReceive implements Runnable{
private int myPort;//监听的端口号
private String name;//发送者名称
private DatagramSocket socket = null;
public ChatReceive(int myPort, String name) throws IOException{
this.myPort = myPort;
this.name = name;
socket = new DatagramSocket(myPort);
}
@Override
public void run() {
while(true){
try {
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
socket.receive(packet);
String msg = new String(packet.getData(), 0, packet.getLength());
System.out.println(name+":"+msg);
if(msg.indexOf("bye") != -1){
break;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
socket.close();
}
}
java
public class ChatDemo01 {
public static void main(String[] args) throws IOException {
System.out.println("学生");
new Thread(new ChatSend("127.0.0.1",8888)).start();
new Thread(new ChatReceive(6666,"老师")).start();
}
}
java
public class ChatDemo02 {
public static void main(String[] args) throws IOException {
System.out.println("老师");
new Thread(new ChatSend("127.0.0.1",6666)).start();
new Thread(new ChatReceive(8888,"学生")).start();
}
}
URL下载网络资源
java
public class URLDemo01 {
public static void main(String[] args) throws Exception {
URL url = new URL("http://localhost:8080/helloworld/index.jsp?username=zhangsan&password=123");
System.out.println(url.getProtocol());//协议
System.out.println(url.getHost());//主机IP
System.out.println(url.getPort());//端口
System.out.println(url.getFile());//全路径
System.out.println(url.getPath());//文件
System.out.println(url.getQuery());//参数
}
}
URL下载网络资源代码
java
public class URLDownload {
public static void main(String[] args) {
HttpURLConnection connection = null;
InputStream is = null;
FileOutputStream fos = null;
try {
//获取URL对象
URL url = new URL("https://gips1.baidu.com/it/u=1410005327,4082018016&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280");
//获取连接
connection = (HttpURLConnection)url.openConnection();
//获取输入流
is = connection.getInputStream();
byte[] buf = new byte[1024];
int len = 0;
fos = new FileOutputStream(new File("cat.png"));
while((len = is.read(buf)) != -1){
fos.write(buf,0,len);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if(fos != null){
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(is != null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(connection != null){
connection.disconnect();//断开连接
}
}
}
}