网络编程三要素:IP、端口号、协议
-
每个程序在设备上的唯一标识
-
每个网络程序都需要绑定一个端口号,传输数据的时候除了确定发到哪台机器上,还要明确发到哪个程序。
-
端口号范围从0-65535
-
编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以下的基本上都被系统程序占用了。
-
常用端口
mysql: 3306、oracle: 1521、web: 80、tomcat: 8080、QQ: 4000、feiQ: 2425
-
协议:
-
UDP 面向无连接,数据不安全,速度快。不区分客户端与服务端。
-
TCP 面向连接(三次握手),数据安全,速度略低。分为客户端和服务端
-
Socket通信原理
-
A:Socket套接字概述:
-
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
-
通信的两端都有Socket。
-
网络通信其实就是Socket间的通信。
-
数据在两个Socket间通过IO流传输。
-
Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port(Socket类似于码头,IO流类似于船只,数据就是货物)。
-
UDP传输
-
1.发送Send
-
创建DatagramSocket, 随机端口号(可以不指定端口号,就是随机端口号)
-
创建DatagramPacket, 指定数据, 长度, 地址, 端口
-
使用DatagramSocket发送DatagramPacket
-
关闭DatagramSocket
-
-
2.接收Receive
-
创建DatagramSocket, 指定端口号
-
创建DatagramPacket, 指定数组, 长度
-
使用DatagramSocket接收DatagramPacket
-
关闭DatagramSocket
-
从DatagramPacket中获取数据
-
-
3.接收方获取ip和端口号
-
String ip = packet.getAddress().getHostAddress();
-
int port = packet.getPort();
-
UDP传输优化
-
发送端Send
package com.heima.socket;
public class Demo1_Send {
/**
* * 1.发送Send
* 创建DatagramSocket, 随机端口号
* 创建DatagramPacket, 指定数据, 长度, 地址, 端口
* 使用DatagramSocket发送DatagramPacket
* 关闭DatagramSocket
* @throws SocketException
* @throws UnknownHostException
*/
public static void main(String[] args) throws Exception {
String str = "what are you 弄啥呢?";
//创建Socket相当于创建码头
DatagramSocket socket = new DatagramSocket();
//创建Packet相当于集装箱
DatagramPacket packet =
new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666);
//发货,将数据发出去
socket.send(packet);
//关闭码头
socket.close();
}
}
package com.heima.socket;
public class Demo2_Send {
/**
* * 1.发送Send
* 创建DatagramSocket, 随机端口号
* 创建DatagramPacket, 指定数据, 长度, 地址, 端口
* 使用DatagramSocket发送DatagramPacket
* 关闭DatagramSocket
* @throws SocketException
* @throws UnknownHostException
*/
public static void main(String[] args) throws Exception {
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//创建Socket相当于创建码头
DatagramSocket socket = new DatagramSocket();
while(true) {
//获取键盘录入的字符串
String line = sc.nextLine();
if("quit".equals(line)) {
break;
}
//创建Packet相当于集装箱
DatagramPacket packet =
new DatagramPacket(line.getBytes(), line.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666);
//发货,将数据发出去
socket.send(packet);
}
//关闭码头
socket.close();
}
}
-
接收端Receive
package com.heima.socket;
public class Demo1_Receive {
/**
** 2.接收Receive
* 创建DatagramSocket, 指定端口号
* 创建DatagramPacket, 指定数组, 长度
* 使用DatagramSocket接收DatagramPacket
* 关闭DatagramSocket
* 从DatagramPacket中获取数据
* @throws Exception
*/
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(6666); //创建Socket相当于创建码头
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);//创建Packet相当于创建集装箱
socket.receive(packet); //接货,接收数据
byte[] arr = packet.getData(); //获取数据
int len = packet.getLength(); //获取有效的字节个数
System.out.println(new String(arr,0,len));
socket.close();
}
}
package com.heima.socket;
public class Demo2_Receive {
/**
** 2.接收Receive
* 创建DatagramSocket, 指定端口号
* 创建DatagramPacket, 指定数组, 长度
* 使用DatagramSocket接收DatagramPacket
* 关闭DatagramSocket
* 从DatagramPacket中获取数据
* @throws Exception
*/
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(6666); //创建Socket相当于创建码头
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);//创建Packet相当于创建集装箱
while(true) {
socket.receive(packet); //接货,接收数据
byte[] arr = packet.getData(); //获取数据
int len = packet.getLength(); //获取有效的字节个数
String ip = packet.getAddress().getHostAddress(); //获取ip地址
int port = packet.getPort(); //获取端口号
System.out.println(ip + ":" + port + ":" + new String(arr,0,len));
}
}
}
UDP传输多线程
-
A发送和接收在一个窗口完成
package com.heima.socket; public class Demo3_MoreThread { /** * @param args */ public static void main(String[] args) { new Receive().start(); new Send().start(); } } class Receive extends Thread { public void run() { try { DatagramSocket socket = new DatagramSocket(6666); //创建Socket相当于创建码头 DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);//创建Packet相当于创建集装箱 while(true) { socket.receive(packet); //接货,接收数据 byte[] arr = packet.getData(); //获取数据 int len = packet.getLength(); //获取有效的字节个数 String ip = packet.getAddress().getHostAddress(); //获取ip地址 int port = packet.getPort(); //获取端口号 System.out.println(ip + ":" + port + ":" + new String(arr,0,len)); } } catch (IOException e) { e.printStackTrace(); } } } class Send extends Thread { public void run() { try { Scanner sc = new Scanner(System.in); //创建键盘录入对象 DatagramSocket socket = new DatagramSocket(); //创建Socket相当于创建码头 while(true) { String line = sc.nextLine(); //获取键盘录入的字符串 if("quit".equals(line)) { break; } DatagramPacket packet = //创建Packet相当于集装箱 new DatagramPacket(line.getBytes(), line.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666); socket.send(packet); //发货,将数据发出去 } socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
TCP协议
-
1.客户端
-
创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器
-
调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
-
输入流可以读取服务端输出流写出的数据
-
输出流可以写出数据到服务端的输入流
-
-
2.服务端
-
创建ServerSocket(需要指定端口号)
-
调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
-
调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
-
输入流可以读取客户端输出流写出的数据
-
输出流可以写出数据到客户端的输入流
-
TCP协议代码优化
客户端服务端1
package com.heima.tcp;
public class Demo1_Client {
/**
* * 1.客户端
* 创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器
* 调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
* 输入流可以读取服务端输出流写出的数据
* 输出流可以写出数据到服务端的输入流
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1", 12345);
InputStream is = socket.getInputStream(); //获取客户端输入流
OutputStream os = socket.getOutputStream(); //获取客户端的输出流
byte[] arr = new byte[1024];
int len = is.read(arr); //读取服务器发过来的数据
System.out.println(new String(arr,0,len)); //将数据转换成字符串并打印
os.write("学习挖掘机哪家强?".getBytes()); //客户端向服务器写数据
socket.close();
}
}
package com.heima.tcp;
public class Demo1_Server {
/**
* * 2.服务端
* 创建ServerSocket(需要指定端口号)
* 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
* 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
* 输入流可以读取客户端输出流写出的数据
* 输出流可以写出数据到客户端的输入流
* @throws IOException
*/
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(12345);
Socket socket = server.accept(); //接受客户端的请求
InputStream is = socket.getInputStream(); //获取客户端输入流
OutputStream os = socket.getOutputStream(); //获取客户端的输出流
os.write("百度一下你就知道".getBytes()); //服务器向客户端写出数据
byte[] arr = new byte[1024];
int len = is.read(arr); //读取客户端发过来的数据
System.out.println(new String(arr,0,len)); //将数据转换成字符串并打印
socket.close();
}
}
- 客户端服务端2
package com.heima.tcp;
public class Demo2_Client {
/**
* * 1.客户端
* 创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器
* 调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
* 输入流可以读取服务端输出流写出的数据
* 输出流可以写出数据到服务端的输入流
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1", 12345);
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //将字节流包装成了字符流
PrintStream ps = new PrintStream(socket.getOutputStream()); //PrintStream中有写出换行的方法
System.out.println(br.readLine());
ps.println("我想报名黑马程序员");
System.out.println(br.readLine());
ps.println("大哭!!!能不能给次机会");
socket.close();
}
}
package com.heima.tcp;
public class Demo2_Server {
/**
* * 2.服务端
* 创建ServerSocket(需要指定端口号)
* 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
* 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
* 输入流可以读取客户端输出流写出的数据
* 输出流可以写出数据到客户端的输入流
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//demo1();
ServerSocket server = new ServerSocket(12345);
while(true) {
final Socket socket = server.accept(); //接受客户端的请求
new Thread() {
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //将字节流包装成了字符流
PrintStream ps = new PrintStream(socket.getOutputStream()); //PrintStream中有写出换行的方法
ps.println("欢迎咨询黑马程序员");
System.out.println(br.readLine());
ps.println("不好意思,爆满了");
System.out.println(br.readLine());
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
public static void demo1() throws IOException {
ServerSocket server = new ServerSocket(12345);
Socket socket = server.accept(); //接受客户端的请求
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //将字节流包装成了字符流
PrintStream ps = new PrintStream(socket.getOutputStream()); //PrintStream中有写出换行的方法
ps.println("欢迎咨询黑马程序员");
System.out.println(br.readLine());
ps.println("不好意思,爆满了");
System.out.println(br.readLine());
socket.close();
}
}