javaSE学习笔记——第26天网络编程、UDP聊天图形化界面的实现、TCP

javaSE学习第二十六天


java知识

网络编程(网络编程概述)

  • A:计算机网络
    • 是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
  • B:网络编程
    • 就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。

网络编程(网络编程三要素之IP概述)

  • 每个设备在网络中的唯一标识
  • 每台网络终端在网络中都有一个独立的地址,我们在网络中传输数据就是使用这个地址。
  • ipconfig:查看本机IP
  • ping:测试连接
  • 本地回路地址:127.0.0.1 255.255.255.255是广播地址
  • IPv4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已经用尽。
  • IPv6:8组,每组4个16进制数。

网络编程(网络编程三要素之端口号概述)

  • 每个程序在设备上的唯一标识
  • 每个网络程序都需要绑定一个端口号,传输数据的时候除了确定发到哪台机器上,还要明确发到哪个程序。
  • 端口号范围从0-65535
  • 编写网络应用就需要绑定一个端口号,尽量使用1024以上的,1024以下的基本上都被系统程序占用了。
  • 常用端口
    • mysql: 3306
    • oracle: 1521
    • web: 80
    • tomcat: 8080
    • QQ: 4000

网络编程(网络编程三要素协议)

  • 为计算机网络中进行数据交换而建立的规则、标准或约定的集合。
  • UDP
    • 面向无连接,数据不安全,速度快。不区分客户端与服务端。
  • TCP
      * 面向连接(三次握手),数据安全,速度略低。分为客户端和服务端。
    • 三次握手: 客户端先向服务端发起请求, 服务端响应请求, 传输数据

网络编程(Socket通信原理)

  • A:Socket套接字概述:
    • 网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
    • 通信的两端都有Socket。
    • 网络通信其实就是Socket间的通信。
    • 数据在两个Socket间通过IO流传输。
    • Socket在应用程序中创建,通过一种绑定机制与驱动程序建立关系,告诉自己所对应的IP和port。

网络编程(UDP传输)

  • 1.发送Send
    • 创建DatagramSocket, 随机端口号
    • 创建DatagramPacket, 指定数据, 长度, 地址, 端口
    • 使用DatagramSocket发送DatagramPacket
    • 关闭DatagramSocket
	public static void main(String[] args) throws Exception {
		String str = "what are you 弄啥来?";
		DatagramSocket socket = new DatagramSocket();
		DatagramPacket packet = new DatagramPacket(str.getBytes(),str.getBytes().length,InetAddress.getByName("127.0.0.1"),6666);
		socket.send(packet);	//将数据发出去
		socket.close();			//关闭	
	}
  • 2.接收Receive
    • 创建DatagramSocket, 指定端口号
    • 创建DatagramPacket, 指定数组, 长度
    • 使用DatagramSocket接收DatagramPacket
    • 关闭DatagramSocket
    • 从DatagramPacket中获取数据
	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);		//接收数据到packet中
		
		byte[] arr = packet.getData();		//从packet中获取数据
		int len = packet.getLength();		//从packet中获取有效的字节个数
		System.out.println(new String(arr,0,len));
		socket.close();
	}
  • 3.接收方获取ip和端口号
    • String ip = packet.getAddress().getHostAddress();
    • int port = packet.getPort();

网络编程(UDP传输优化,可以发送任意内容)

  • 接收端Receive

  •   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();
      	System.out.println(ip + ":" + new String(arr,0,len));
      }
    
  • 发送端Send

      DatagramSocket socket = new DatagramSocket();		//创建socket相当于创建码头
      Scanner sc = new Scanner(System.in);
      
      while(true) {
      	String str = sc.nextLine();
      	if("quit".equals(str))
      		break;
      	DatagramPacket packet = 							//创建packet相当于创建集装箱
      			new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666);
      	socket.send(packet);			//发货
      }
      socket.close();
    

网络编程(UDP传输多线程)

  • A发送和接收在一个窗口完成

      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();
      				System.out.println(ip + ":" + new String(arr,0,len));
      			}
      		} catch (IOException e) {
      			
      			e.printStackTrace();
      		}
      	}
      }
    
      class Send extends Thread {
      	public void run() {
      		try {
      			DatagramSocket socket = new DatagramSocket();		//创建socket相当于创建码头
      			Scanner sc = new Scanner(System.in);
      			
      			while(true) {
      				String str = sc.nextLine();
      				if("quit".equals(str))
      					break;
      				DatagramPacket packet = 							//创建packet相当于创建集装箱
      						new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666);
      				socket.send(packet);			//发货
      			}
      			socket.close();
      		}  catch (IOException e) {
      			
      			e.printStackTrace();
      		}
      	}
      }
    

网络编程(UDP聊天图形化界面)

  • .jar文件下载链接点我跳转https://download.csdn.net/download/qq_43594119/12139702

    package com.yinglongwu.socket;
    import java.awt.BorderLayout;
    import java.awt.Button;
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Frame;
    import java.awt.Panel;
    import java.awt.TextArea;
    import java.awt.TextField;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyEvent;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.io.BufferedWriter;
    import java.io.ByteArrayOutputStream;
    import java.io.FileInputStream;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.SocketException;
    import java.net.UnknownHostException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class Demo2_GUIChat extends Frame {
    	
    	private TextField tf;
    	private Button send;
    	private Button log;
    	private Button clear;
    	private Button shake;
    	private TextArea viewText;
    	private TextArea sendText;
    	private DatagramSocket socket;
    	private BufferedWriter bw;
    
    	//GUI聊天
    	public Demo2_GUIChat() {
    		init();
    		southPanel();
    		centerPanel();
    		event();
    	}
    
    	public void event() {
    		this.addWindowListener(new WindowAdapter() {
    			@Override
    			public void windowClosing(WindowEvent e) {
    				socket.close();
    				try {
    					bw.close();
    				} catch (IOException e1) {
    					
    					e1.printStackTrace();
    				}
    				System.exit(0);
    			}
    		});
    		send.addActionListener(new ActionListener() {
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				try {
    					send();
    				} catch (IOException e1) {
    					e1.printStackTrace();
    				}
    			}
    		});
    		log.addActionListener(new ActionListener() {
    			
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				try {
    					logFile();
    				} catch (IOException e1) {
    					e1.printStackTrace();
    				}
    			}
    		});
    		clear.addActionListener(new ActionListener() {
    			
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				viewText.setText(null);
    			}
    		});
    		shake.addActionListener(new ActionListener() {
    			
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				try {
    					send(new byte[]{-1},tf.getText());
    				} catch (IOException e1) {
    					e1.printStackTrace();
    				}
    			}
    		});
    		sendText.addKeyListener(new KeyAdapter() {
    			@Override
    			public void keyReleased(KeyEvent e) {
    				//if(e.getKeyCode() == KeyEvent.VK_ENTER) {		//按回车键发送
    				if(e.getKeyCode() == KeyEvent.VK_ENTER && e.isControlDown()) {		//按住ctrl+回车发送
    					try {
    						send();
    					} catch (IOException e1) {
    						
    						e1.printStackTrace();
    					}
    				}
    			}
    		});
    	}
    
    	private void shake() {
    		int x = this.getLocation().x;		//获取横坐标位置
    		int y = this.getLocation().y;		//获取纵坐标位置
    		
    		for(int i =0;i<=20;i++) {
    			try {
    				this.setLocation(x + 20, y + 20);
    				Thread.sleep(10);
    				this.setLocation(x + 20, y - 20);
    				Thread.sleep(10);
    				this.setLocation(x -20 , y + 20);
    				Thread.sleep(10);
    				this.setLocation(x - 20, y - 20);
    				Thread.sleep(10);
    				this.setLocation(x, y);
    			} catch (InterruptedException e) {
    				
    				e.printStackTrace();
    			}
    			
    		}
    	}
    	
    	private void logFile() throws IOException {
    		bw.flush(); 	//刷新缓冲区
    		FileInputStream fis = new FileInputStream("config.txt");
    		ByteArrayOutputStream baos = new ByteArrayOutputStream();	//在内存中创建缓冲区
    		
    		int len;
    		byte[] arr = new byte[8192];
    		while((len = fis.read(arr)) != -1) {
    			baos.write(arr,0,len);
    		}
    		
    		String str = baos.toString();		//将内存中的内容转换成了字符串
    		viewText.setText(str);
    		
    		fis.close();
    	}
    	
    	private void send(byte[] arr, String ip) throws IOException {
    		DatagramPacket packet = new DatagramPacket(arr,arr.length,InetAddress.getByName(ip),9999);
    		socket.send(packet);							//发送数据
    	}
    	
    	private void send() throws IOException {
    		String message = sendText.getText();			//获取发送内容
    		String ip = tf.getText();						//获取ip地址
    		ip = ip.trim().length() == 0 ? "255.255.255.255" : ip;		//如果ip栏没写明地址,就默认为255.255.255.255向所有人发送
    		
    		send(message.getBytes(),ip);
    		
    		String time = getCurrentTime();		//获取当前时间
    		String str = time + " 我 对 " + (ip.equals("255.255.255.255") ? "所有人" : ip) + " 说: \r\n" + message + "\r\n\r\n";
    		viewText.append(str);		//把文本放追加在显示区域
    		bw.write(str);				//将信息写到数据库中
    		sendText.setText("");				//把发送的文本清空
    		
    		
    	}
    	
    	private String getCurrentTime() {
    		Date d = new Date();
    		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
    		return sdf.format(d);
    	}
    
    	private void centerPanel() {	//如果显示不出来效果把窗口最大化
    		Panel center = new Panel();					//创建中间的Panel
    		viewText = new TextArea();
    		sendText = new TextArea(5,1);
    		center.setLayout(new BorderLayout());		//设置为边界布局管理器
    		center.add(sendText,BorderLayout.SOUTH);	//发送的文本区域放在南边
    		center.add(viewText,BorderLayout.CENTER);	//显示的区域放在中间
    		viewText.setEditable(false);				//设置不可编辑
    		viewText.setBackground(Color.WHITE);		//设置背景颜色为白色
    		sendText.setFont(new Font("xxx",Font.PLAIN,15));	//设置发送字体
    		viewText.setFont(new Font("xxx",Font.PLAIN,15));	//设置接收字体
    		this.add(center,BorderLayout.CENTER);
    	}
    
    	private void southPanel() {
    		Panel south = new Panel();			//创建南边的Panel
    		tf = new TextField(15);
    		tf.setText("127.0.0.1"); 		//设置默认的ip地址
    		send = new Button("发 送");
    		log = new Button("聊天记录");
    		clear = new Button("清 屏");
    		shake = new Button("震 动");
    		south.add(tf);
    		south.add(send);
    		south.add(log);
    		south.add(clear);
    		south.add(shake);
    		this.add(south,BorderLayout.SOUTH);	//将panel放在frame南边
    	}
    
    	public void init() {
    		this.setLocation(500, 50);
    		this.setSize(400, 600);
    		new Receive().start();
    		try {
    			socket = new DatagramSocket();
    			bw = new BufferedWriter(new FileWriter("config.txt",true));	//需要在尾部追加
    		} catch (Exception e) {
    			
    			e.printStackTrace();
    		}
    		this.setVisible(true);
    	}
    	
    	private class Receive extends Thread{	//接收和发送需要同时执行,所以定义成多线程
    		public void run() {
    			try {
    				DatagramSocket socket = new DatagramSocket(9999);
    				DatagramPacket packet = new DatagramPacket(new byte[8192],8192);
    				while(true) {
    					socket.receive(packet);						//接收信息
    					byte[] arr = packet.getData();				//获取字节数据
    					int len = packet.getLength();				//获取有效的字节数据
    					if(arr[0] == -1 && len ==1) {				//如果发过来的数组第一个存储的值是-1,并且数组长度是1
    						shake();		//调用窗口震动方法
    						continue;		//终止本次循环,继续下次循环,因为震动后不需要执行下面的代码
    					}
    					String message = new String(arr,0,len);		//转换成字符串
    					String time = getCurrentTime();				//获取当前时间
    					String ip = packet.getAddress().getHostAddress();	//获取ip地址
    					String str = time + " " + ip + " 对 我 说: \r\n" + message + "\r\n\r\n";
    					viewText.append(str);
    					bw.write(str);
    				}
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	
    	public static void main(String[] args) {
    		new Demo2_GUIChat();
    	}
    
    }
    

网络编程(TCP协议)

  • 1.客户端
    • 创建Socket连接服务端(指定ip地址,端口号)通过ip地址找对应的服务器
    • 调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
    • 输入流可以读取服务端输出流写出的数据
    • 输出流可以写出数据到服务端的输入流
  • 2.服务端
    • 创建ServerSocket(需要指定端口号)
    • 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
    • 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
    • 输入流可以读取客户端输出流写出的数据
    • 输出流可以写出数据到客户端的输入流

网络编程(TCP协议代码优化)

  • 客户端

      Socket socket = new Socket("127.0.0.1", 9999);		//创建Socket指定ip地址和端口号
      InputStream is = socket.getInputStream();			//获取输入流
      OutputStream os = socket.getOutputStream();			//获取输出流
      BufferedReader br = new BufferedReader(new InputStreamReader(is));
      PrintStream ps = new PrintStream(os);
      
      System.out.println(br.readLine());
      ps.println("我想搜索...");
      System.out.println(br.readLine());
      ps.println("再见");
      socket.close();
    
  • 服务端

      ServerSocket server = new ServerSocket(9999);	//创建服务器
      Socket socket = server.accept();				//接受客户端的请求
      InputStream is = socket.getInputStream();		//获取输入流
      OutputStream os = socket.getOutputStream();		//获取输出流
      
      BufferedReader br = new BufferedReader(new InputStreamReader(is));
      PrintStream ps = new PrintStream(os);
      
      ps.println("百度一下,你就知道");
      System.out.println(br.readLine());
      ps.println("...是...");
      System.out.println(br.readLine());
      server.close();
      socket.close();
    

网络编程(服务端是多线程的)

ServerSocket server = new ServerSocket(9999);	//创建服务器
	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());
					ps.println("百度一下,你就知道");
					System.out.println(br.readLine());
					ps.println("...是...");
					System.out.println(br.readLine());
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}.start();
	}
}

网络编程(练习)

  • 客户端向服务器写字符串(键盘录入),服务器(多线程)将字符串反转后写回,客户端再次读取到是反转后的字符串

  • 客户端代码 Client.java

      package com.yinglongwu.tcp;
      
      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintStream;
      import java.net.Socket;
      import java.net.UnknownHostException;
      import java.util.Scanner;
      
      public class Demo1_Client {
      	/*客户端向服务器写字符串(键盘录入),服务器(多线程)将字符串反转后写回,客户端再次读取到是反转后的字符串
      	 * */
      	public static void main(String[] args) throws UnknownHostException, IOException {
      		Scanner sc = new Scanner(System.in);			//创建键盘录入对象
      		Socket socket = new Socket("127.0.0.1",54321);	//创建客户端,指定ip地址和端口号
      		
      		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));	//获取输入流
      		PrintStream ps = new PrintStream(socket.getOutputStream());		//获取输出流
      		
      		ps.println(sc.nextLine());		//将字符串写到服务器去
      		System.out.println(br.readLine()); 	//将反转后的结果读出来
      		
      		socket.close();
      	}
      
      }
    
  • 服务端代码 Server.java

      package com.yinglongwu.tcp;
      
      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintStream;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      public class Demo1_Server {
      
      	public static void main(String[] args) throws IOException {
      		ServerSocket server = new ServerSocket(54321);
      		System.out.println("服务器启动,绑定54321端口");
      		
      		while(true) {
      			final Socket socket = server.accept();		//接受客户端请求
      			
      			new Thread() {								//开启一条线程
      				public void run() {
      					BufferedReader br;
      					try {
      						br = new BufferedReader(new InputStreamReader(socket.getInputStream()));	//获取输入流
      						PrintStream ps = new PrintStream(socket.getOutputStream());		//获取输出流
      						
      						String line = br.readLine();	//将客户端写过来的数据读取出来
      						line = new StringBuilder(line).reverse().toString();		//字符串反转
      						ps.print(line);
      						socket.close();
      					} catch (IOException e) {
      						
      						e.printStackTrace();
      					}	//获取输入流
      					
      				}
      			}.start();
      		}
      	}
      
      }
    

网络编程(练习)

  • 客户端向服务器上传文件

  • 客户端代码 Client.java

      package com.yinglongwu.tcp;
      
      import java.io.BufferedReader;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintStream;
      import java.net.Socket;
      import java.net.UnknownHostException;
      import java.util.Scanner;
      
      public class Demo2_UpdateClient {
      
      	public static void main(String[] args) throws UnknownHostException, IOException {
      		//1.提示输入要上传的文件路径,验证路径是否存在以及是否是文件夹
      		File file = getFile();
      		//2.发送文件名到服务器
      		Socket socket = new Socket("127.0.0.1",12345);
      		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      		PrintStream ps = new PrintStream(socket.getOutputStream());
      		ps.println(file.getName());
      		//6.接收结果,如果存在给与提示,程序直接退出
      		String result = br.readLine();
      		if("文件已存在".equals(result)) {
      			System.out.println("您上传的文件已经存在,请不要重复上传");
      			socket.close();
      			return;
      		}
      		//7.如果不存在,定义FileInputStream读取文件,写出到网络
      		FileInputStream fis = new FileInputStream(file);
      		byte[] arr = new byte[8192];
      		int len;
      		while((len = fis.read(arr)) != -1) {
      			ps.write(arr,0,len);
      		}
      		fis.close();
      		socket.close();
      	}
      	
      	private static File getFile() {
      		Scanner sc = new Scanner(System.in);
      		System.out.println("请输入一个文件路径:");
      		
      		while(true) {
      			String line = sc.nextLine();
      			File file = new File(line);
      			
      			if(!file.exists()) {
      				System.out.println("您录入的文件路径不存在,请重新录入:");
      			}else if(file.isDirectory()) {
      				System.out.println("您录入的是文件夹路径,请输入一个文件路径:");
      			}else {
      				return file;
      			}
      		}
      	}
      
      }
    
  • 服务端代码 Server.java

      package com.yinglongwu.tcp;
      
      import java.io.BufferedReader;
      import java.io.File;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import java.io.InputStreamReader;
      import java.io.PrintStream;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      public class Demo2_UpdateServer {
      
      	public static void main(String[] args) throws IOException {
      		//3.建立多线程的的服务器
      		ServerSocket server = new ServerSocket(12345);
      		System.out.println("服务器启动,绑定12345端口号");
      		//4.读取文件名
      		while(true) {
      			final Socket socket = server.accept();
      			new Thread() {
      				public void run() {
      					try {
      						InputStream is = socket.getInputStream();
      						BufferedReader br = new BufferedReader(new InputStreamReader(is));
      						PrintStream ps = new PrintStream(socket.getOutputStream());
      						String fileName = br.readLine();
      						
      						//5.判断文件是否存在,将结果发回客户端
      						File dir = new File("update");
      						dir.mkdir();							//创建文件夹
      						File file = new File(dir,fileName);		//封装成File对象
      						
      						if(file.exists()) {						//如果服务器已经存在这个文件
      							ps.print("文件已存在");				//提示客户端文件已存在
      							socket.close();						//关闭socket
      							return;
      						}else {
      							ps.println("文件不存在");
      						}
      						//8.定义FileOutputStream,从网络读取数据,存储到本地
      						FileOutputStream fos = new FileOutputStream(file);
      						byte[] arr = new byte[8192];
      						int len;
      						while((len = is.read(arr)) != -1) {
      							fos.write(arr,0,len);
      						}
      						
      						fos.close();
      						socket.close();
      					} catch (IOException e) {
      						
      						e.printStackTrace();
      					}
      				}
      			}.start();
      		}
      	}
      
      }
    

你可能感兴趣的:(javaSE)