网络编程三要素
IP,端口,协议。
1.IP:在Internet上,每一台通信实体(这个通信实体可以是路由器的某一端口,计算机和服务器等设备)都有唯一表示的IP地址,之前都是IPv4的但在2011年已经用尽,现在正向ipv6时代迈进
2.端口:在设备上的唯一标识,范围在0–65535之间,编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以下的基本上都被系统程序占用了。
3.协议:为计算机网络中进行数据交换而建立的规则、标准或约定的集合。
UDP
面向无连接,数据不安全,速度快。不区分客户端与服务端。
TCP
面向连接(三次握手),数据安全,速度略低。分为客户端和服务端。
三次握手: 客户端先向服务端发起请求, 服务端响应请求, 传输数据
Socket套接字
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
通信的两端都有Socket。
网络通信其实就是Socket间的通信。
数据在两个Socket间通过IO流传输。
Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port
UDP的传输
发送Send
创建DatagramSocket, 随机端口号
创建DatagramPacket, 指定数据, 长度, 地址, 端口
使用DatagramSocket发送DatagramPacket
关闭DatagramSocket
public static void main(String[] args) throws IOException {
String s = "为梦想奋斗";//要发送的数据
DatagramSocket ds = new DatagramSocket();//创建Socket对象 相当于创建码头
DatagramPacket dsp = //创建Packet 相当于创建集装箱
new DatagramPacket(s.getBytes(), s.getBytes().length,InetAddress.getByName("127.0.0.1"),12345);
ds.send(dsp); //发送数据
ds.close();
}
接收Receive
创建DatagramSocket, 指定端口号
创建DatagramPacket, 指定数组, 长度
使用DatagramSocket接收DatagramPacket
关闭DatagramSocket
从DatagramPacket中获取数据
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(12345); //创建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();
}
UDP传输的优化
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();//创建Socket对象 相当于创建码头
Scanner sc = new Scanner(System.in);//键盘录入
while(true){
String line = sc.nextLine();//接收键盘录入内容
if("over".equals(line)){ //相当于图形化界面的差号
break;
}
DatagramPacket dsp = //创建Packet 相当于创建集装箱
new DatagramPacket(line.getBytes(), line.getBytes().length,InetAddress.getByName("127.0.0.1"),12345);
ds.send(dsp); //发送数据
}
ds.close();
}
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(12345); //创建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().getCanonicalHostName();//获取IP地址
int port = packet.getPort(); //获取端口号
System.out.println(ip + ":" + port + ":" + new String(arr,0,len));
}
}
}
TCP传输
客户端
普通方式和优化方式
public static void main(String[] args) throws UnknownHostException, IOException {
//demo();
Socket socket = new Socket("127.0.0.1",9999);//创建Socket,并指定IP和端口号
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//对输入流包装
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("相信自己一定可以");//向服务器写出数据
System.out.println(br.readLine());//读取服务器的内容并打印
socket.close();
}
private static void demo() throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1",9999);//创建Socket,并指定IP和端口号
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());
}
}
服务端
普通方式
private static void demo() throws IOException {
ServerSocket server = new ServerSocket(9999);//创建ServerSocket t对象并连接端口
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));//将数组转化为字符串
server.close();
socket.close();
}
优化方式
private static void demo1() throws IOException {
ServerSocket server = new ServerSocket(9999);//创建ServerSocket t对象并连接端口
Socket socket = server.accept(); //接收客户端的请求
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//对输入流包装
PrintStream ps = new PrintStream(socket.getOutputStream());
System.out.println(br.readLine());//读取服务器的内容并打印
ps.println("加油加油加油"); //向服务器写出数据
socket.close();//关闭套接字,顺便关闭流
}
多线程方式
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9999);//创建ServerSocket t对象并连接端口
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());
System.out.println(br.readLine());//读取服务器的内容并打印
ps.println("努力努力努力"); //向服务器写出数据
socket.close();//关闭套接字,顺便关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
练习:客户端向服务器写字符串,服务器将字符串反转后写回,客户端再次读取到是反转后的字符串
客户端:
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1", 23445);//创建客户端对象并指定IP和端口
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream ps = new PrintStream(socket.getOutputStream());
Scanner sc = new Scanner(System.in);
ps.println(sc.nextLine()); //将键盘录入的字符串放在服务器中
System.out.println(br.readLine());//打印反转后的字符串
socket.close();
}
服务端:
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(23445);//创建服务端服务器,并连接端口
System.out.println("服务器启动");
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());
String line = br.readLine();//获取字符串
line = new StringBuilder(line).reverse().toString();//将字符串放在Stringbuilder中反转并转回字符串
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}