网络编程与内部类

网络编程

1 概念

socket:网络编程
       实现网络中 不同电脑之间的数据传输

IP地址(Internet Protocol Address)是指互联网协议地址   
      IPV4: 4个1个byte的十进制数字  0.0.0.0 -- 255.255.255.255   
      IPV6: 8个2个byte的16进制数字  0.0.0.0.0.0.0.0  -- ffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff
      它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
      一个字符串用于唯一标识互联网上主机
      127.0.0.1 / localhost  表示本地主机
域名: ip地址不宜与记忆  通过一段字符串来和ip地址一一对应
域名服务器:DNS 解析域名与ip的对应关系
PORT:端口  逻辑端口 电脑上安装的所有软件都会分配一个唯一的编号 0-65535 实现互联网数据传输
      注意10000以下的端口 不要使用  默认被操作系统的软件使用    

2 socket分类

* TCP:Transmission Control Protocol  传输控制协议
       可控的 端对端的  字节流传输协议
       类似于:打固定电话
* UDP:User Datagram Protocol  用户数据报协议    
       不可靠的 无需连接的 报文流传输协议
       类似于:发电部

3 TCP

tcp的两端:客户端和服务器端
被动接电话的---服务器端
主动打电话的---客户端
主要涉及的类:ServerSocket+Socket
           Socket:套接字/传输通道

3.1方法

    *ServerSocket:服务器套接字
     *构造方法:ServerSocket(int port)  开启服务并制定端口
     *普通方法:Socket accept()  :等到和获取客户端连接
     *        void close()  :关闭服务
     *        
     *Socket:套接字/传输通道
     *构造方法:Socket(String host, int port)  创建连接 并制定服务器端的ip和port
     *普通方法:InputStream getInputStream()  :获取输入流
     *       OutputStream getOutputStream()  :获取输出流
     *       void close()  :关闭socket
     *       InetAddress getInetAddress()   获取自己的ip
			 InetAddress getLocalAddress()  获取对方的ip
			 int getLocalPort()            获取自己的端口
			 int getPort()                 获取对方的端口

3.1 案例

  • 服务器端
package com.zhiyou100.day14_socket;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Demo01TCP_Server {
    /*tcp服务器端
     *被动接电话的一端
     *1 安装电话 买个号::::创建一个ServerSocket并开启一个端口
     *2 等待别人的电话::::等待客户端的连接
     *3 接通电话 说和听::::接受和发送信息 
     *4 挂断电话:::::关闭服务 
     * */
	public static void main(String[] args)throws Exception {
		//1 开启服务:创建一个ServerSocket并开启一个端口
		ServerSocket server=new ServerSocket(10086);
		System.out.println("服务器端开启:::"+10086);
		//2 获取客户端的连接
		Socket socket=server.accept();//阻塞方法:
		//3 获取socket的输入流和输出流 用于接受和发送信息
		InputStream in=socket.getInputStream();
		OutputStream out=socket.getOutputStream();
		//4 接受和发送信息
		byte[] arr=new byte[1024];
		int n=in.read(arr);
		System.out.println("服务器端接收到客户端的信息是:"+new String(arr, 0, n));
		
		System.out.println("服务器端getLocalPort:"+socket.getLocalPort());
		System.out.println("服务器端getLocalAddress:"+socket.getLocalAddress().getHostName());
		System.out.println("服务器端getInetAddress:"+socket.getInetAddress().getHostName());
		System.out.println("服务器端getPort:"+socket.getPort());
		
		out.write("好的!收到!再见".getBytes());
		
		//5 关闭服务
		server.close();

	}
}
  • 客户端
package com.zhiyou100.day14_socket;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Demo01TCP_Client {
    /*TCP:客户端
     * 客户端:主动打电话
     * 1 准备电话  准备电话线 拨通对方的号码----创建socket 指定服务器端的ip和port
     * 2 电话接通 说和听----获取输入流和输出流 进行数据传输
     * 3 挂断电话 撤销电话线----关闭socket
     * */
	public static void main(String[] args)throws Exception {
		//1 创建socket 指定服务器端的ip和port
		Socket socket=new Socket("192.168.118.107", 10086);
		System.out.println("客户端创建连接成功!——————————");
		//2 获取输入流和输出流
		InputStream in=socket.getInputStream();
		OutputStream out=socket.getOutputStream();
		//3 发送和接受数据
		out.write("你好,服务器端:给我带个包子!".getBytes());
		byte[] arr=new byte[1024];
		int n=in.read(arr);
		System.out.println("客户端接收到服务器端的信息是:"+new String(arr,0,n));
		System.out.println("客户端getLocalPort:"+socket.getLocalPort());
		System.out.println("客户端getLocalAddress:"+socket.getLocalAddress().getHostName());
		System.out.println("客户端getInetAddress:"+socket.getInetAddress().getHostName());
		System.out.println("客户端getPort:"+socket.getPort());
		//4 关闭sokcet
		socket.close();
	}
}

3.2 实现互发信息

  • 客户端
package com.zhiyou100.day14_socket;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class Demo02TCP_Client {
    //客户端从键盘读取信息  把读取的信息发给服务器端  然后再接受    直到发送了886
	public static void main(String[] args) throws Exception{
		//1 创建socket  制定服务器的ip和端口
		Socket socket=new Socket("localhost", 10086);
		//2 获取输入流和输出流
		InputStream in=socket.getInputStream();
		OutputStream out=socket.getOutputStream();
		//3 获取系统输入流
		BufferedReader bin=new BufferedReader(new InputStreamReader(System.in));
		
		while(true){
			String line=bin.readLine();//从键盘读取一行信息
			out.write(line.getBytes());//把读取的信息通过socket发送给客户端
			if(line.equals("886")){
				break;
			}
			byte[] arr=new byte[1024];
			int n=in.read(arr);
			String message=new String(arr, 0,n);
			System.out.println("接收到10086的信息是:"+message);
		}
		//4 关闭流和socket
		//系统相关的流不能关闭
		socket.close();
	}	
}
  • 服务器端
package com.zhiyou100.day14_socket;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Demo02TCP_Server {
    //: 服务器端接受信息:把信息转换后发送给客户端
	public static void main(String[] args) throws Exception{
		  //1 开启服务
		  ServerSocket ss=new ServerSocket(10086);
		  //2 获取连接
		  Socket socket=ss.accept();
		  //3 获取视如流和输出流
		  InputStream in=socket.getInputStream();
		  OutputStream out=socket.getOutputStream();
		   
		  //4 接受和发送数据
		 
		  while(true){
			  byte[] arr=new byte[1024];
			  int n=in.read(arr); 
			  String message=new String(arr,0,n);
			  if(message.equals("886")){//如果接受到886就结束
				  break;
			  }
			  message=change(message);
			  out.write(message.getBytes());
		  }
		  //5 关闭服务
		  ss.close();

	}
	public static String change(String s){
		String ss="";
		for(int i=0;i<s.length();i++){
			char c=s.charAt(i);
			if(Character.isUpperCase(c)){
				ss+=Character.toLowerCase(c);
			}else if(Character.isLowerCase(c)){
				ss+=Character.toUpperCase(c);
			}else if(!Character.isDigit(c)){
				ss+=c;
			}
		}
		return ss;
	}
}

3.3 实现文件上传

  • 客户端
package com.zhiyou100.day14_socket;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Demo03TCP_Client {
    //客户端:先发送源文件的名字  再发送源文件的内容 
	public static void main(String[] args) throws Exception{
		//1 创建socket
		Socket socket=new Socket("localhost",10086);
		//2 获取流
		InputStream in=socket.getInputStream();
		OutputStream out=socket.getOutputStream();
		File yuan=new File("C:\\Users\\Administrator\\Desktop\\imgs\\2.jpg");
		BufferedInputStream bin=new BufferedInputStream(new FileInputStream(yuan));
		out.write(yuan.getName().getBytes());//发送文件的名字
		byte[] arr=new byte[1024];
		int n;
		while((n=bin.read(arr))!=-1){
			out.write(arr, 0, n);
		}
		//关闭socket的输出流
		socket.shutdownOutput();
		//4 关闭流和socket
		socket.close();
		bin.close();
	}
	//xml  swing    socket io  thread
}

  • 服务器端
package com.zhiyou100.day14_socket;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Demo03TCP_Server {
     //文件上传:先传递文件名 再传递文件内容
	public static void main(String[] args)throws Exception {
		//1 开启服务
		ServerSocket ss=new ServerSocket(10086);
		//2 获取连接
		Socket socket=ss.accept();
		//3 获取流
		InputStream in=socket.getInputStream();
		OutputStream out=socket.getOutputStream();
		//4 先获取文件名字:
		byte[] arr=new byte[1024];//默认第一次发送的信息就是文件名字
		int n=in.read(arr);
		String fileName=new String(arr,0,n);
		//创建输出流与目的文件关联
		BufferedOutputStream bout=
				new BufferedOutputStream(new FileOutputStream("src/com/zhiyou100/day14_socket/"+fileName));
		//一边从socket中读信息 一边把读取的信息写到目的文件中
		while(true){
			n=in.read(arr);
			if(n==-1){
				break;
			}
			bout.write(arr, 0, n);
		}
		//关闭流和服务
		bout.close();
		ss.close();
	}
}

4 UDP

4.1 方法

     * udp:报文流传输协议
     * 主要类:DatagramPacket+DatagramSocket
     * DatagramPacket:对发送和接受的信息的封装
     * 构造方法:(创建报文对象:带地址用于发送 不带地址用与接受)
     *      DatagramPacket(byte[] buf, int offset, int length):用于接受的报文 
            DatagramPacket(byte[] buf, int offset, int length, InetAddress ip, int port) 用于发送的报文
       普通方法:      
			InetAddress getAddress() :获取对方的ip
			int getPort() :获取对方的port
			byte[] getData() 
			int getLength() 
       
       DatagramSocket:报文流的套接字
       构造方法:
              DatagramSocket(int port) :指定开启的打开
       普通方法:       
             void receive(DatagramPacket p) :接受报文对象
			 void send(DatagramPacket p) :发送报文
			 void close()   :关闭套接字
			 InetAddress getLocalAddress() :获取本地的ip
             int getLocalPort()  :获取本地的port

4.2 案例

  • 接受方
//接收方
		//1 创建socket
		DatagramSocket scoket=new DatagramSocket(10010);
		//2 创建一个空的datagramepacket用于接受信息
		DatagramPacket packet=new DatagramPacket(new byte[1024], 1024);
		//3接受信息
		scoket.receive(packet);
		System.out.println("10010:packet.getPort="+packet.getPort());
		System.out.println("10010:packet.getAddress="+packet.getAddress());
		//System.out.println("10010:scoket.getPort()="+scoket.getPort());
		//System.out.println("10010:scoket.getInetAddress()="+scoket.getInetAddress().getHostName());
		System.out.println("10010:scoket.getLocalPort()="+scoket.getLocalPort());
		System.out.println("10010:scoket.getLocalAddress()="+scoket.getLocalAddress().getHostName());
		//4 解析信息
		String message=new String(packet.getData(),0,packet.getLength());
		System.out.println("10010接收到的信息是:"+message);
		//5 关闭socket
		scoket.close();
  • 发送方
//1 创建datagramsocket
		DatagramSocket socket=new DatagramSocket(10086);
		//2 创建一个datagrampacket
		String message="udp你好!";
		byte[] arr=message.getBytes();
		DatagramPacket packet=new DatagramPacket(arr, arr.length, InetAddress.getByName("127.0.0.1"), 10010);
		//3 发送信息
		socket.send(packet);
		System.out.println("10086:packet.getPort="+packet.getPort());
		System.out.println("10086:packet.getAddress="+packet.getAddress());
		//System.out.println("10086:scoket.getPort()="+socket.getPort());
		//System.out.println("10086:scoket.getInetAddress()="+socket.getInetAddress().getHostName());
		System.out.println("10086:scoket.getLocalPort()="+socket.getLocalPort());
		System.out.println("10086:scoket.getLocalAddress()="+socket.getLocalAddress().getHostName());
		//4 关闭socket
		socket.close();

4.3 实现互发信息

  • 先发送方
package com.zhiyou100.day14_socket;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class Demo05UDP_1 {
	//键盘读取信息  把信息发送给对方 接受对方的信息:对方把信息转换
	public static void main(String[] args) throws Exception{
		    //1 创建socket
		    DatagramSocket socket=new DatagramSocket(10086);
		    //2 获取系统输入流
		    BufferedReader bin=new BufferedReader(new InputStreamReader(System.in));
		    //逐行读取键盘的信息
		    while(true){
		    	String line=bin.readLine();
		    	byte[] arr=line.getBytes();
		    	//创建datagrampacket封装发送的信息
		    	DatagramPacket sendPacket=
		    			new DatagramPacket(arr, arr.length, InetAddress.getByName("localhost"), 10010);
		    	//发送信息
		    	socket.send(sendPacket);
		    	if(line.equals("886")){
		    		break;
		    	}
		    	//创建一个空的datagrampacket接受信息
		    	DatagramPacket receivePacket=new DatagramPacket(new byte[1024], 1024);
		    	//接受信息
		    	socket.receive(receivePacket);
		    	//解析数据
		    	String message=new String(receivePacket.getData(),0,receivePacket.getLength());
		    	System.out.println(socket.getLocalPort()+"接收到"+receivePacket.getPort()+"的信息是:"+message);
		    }
		    //关闭socket
		    socket.close();
	}
}

  • 后接收方
package com.zhiyou100.day14_socket;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Demo05UDP_2 {

	public static void main(String[] args) throws Exception{
		//1 创建socket
		DatagramSocket socket=new DatagramSocket(10010);
		//2 循环的接受和发送
		while(true){
			//定义一个空的报文对象 接受信息
			DatagramPacket receivePacket=new DatagramPacket(new byte[1024], 1024);
			socket.receive(receivePacket);
			//解析信息
			String message=new String(receivePacket.getData(),0,receivePacket.getLength());
			System.out.println(socket.getLocalPort()+"接收到"+receivePacket.getPort()+"的信息是:"+message);
			if(message.equals("886")){
				break;
			}
			//对字符串进行循环
			message=change(message);
			byte[] arr=message.getBytes();
			DatagramPacket sendPacket=
					new DatagramPacket(arr, arr.length,receivePacket.getAddress(),receivePacket.getPort());
			socket.send(sendPacket);
			
		}
		//3关闭socket
		socket.close();

	}
	public static String change(String s){
		String ss="";
		for(int i=0;i<s.length();i++){
			char c=s.charAt(i);
			if(Character.isUpperCase(c)){
				ss+=Character.toLowerCase(c);
			}else if(Character.isLowerCase(c)){
				ss+=Character.toUpperCase(c);
			}else if(!Character.isDigit(c)){
				ss+=c;
			}
		}
		return ss;
	}
	

}

4.4 实现文件上传

  • Server服务端
package com.test.test4;

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


//发送
public class UDP_Upload_01 {

	public static void main(String[] args) throws IOException {
		
		DatagramSocket socket = new DatagramSocket(10086);
		
		String srcFile = "ServerFile\\Day01\\day01\\ListFilesTest.java";
		
		byte[] buff = srcFile.getBytes();
		
		DatagramPacket sendPacket = new DatagramPacket(buff, buff.length, InetAddress.getByName("localhost"), 10010);
		
		socket.send(sendPacket);
		
		DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
		
		socket.receive(receivePacket);
		
		String message = new String(receivePacket.getData(),0,receivePacket.getLength());
		
		System.out.println(message);
		
		socket.close();
			

	}

}

  • Customer客户端
package com.test.test4;

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


//发送
public class UDP_Upload_01 {

	public static void main(String[] args) throws IOException {
		
		DatagramSocket socket = new DatagramSocket(10086);
		
		String srcFile = "ServerFile\\Day01\\day01\\ListFilesTest.java";
		
		byte[] buff = srcFile.getBytes();
		
		DatagramPacket sendPacket = new DatagramPacket(buff, buff.length, InetAddress.getByName("localhost"), 10010);
		
		socket.send(sendPacket);
		
		DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
		
		socket.receive(receivePacket);
		
		String message = new String(receivePacket.getData(),0,receivePacket.getLength());
		
		System.out.println(message);
		
		socket.close();
	}
}

5 模拟QQ群聊

  • 客户端
package com.zhiyou100.day14_socket;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class Demo06ChatClient {

	public static void main(String[] args)throws Exception {
		  //注意1:所有的客户端只需要给服务器连接即可
		  //注意2: 对于客户端的socket的输入和输出需要使用多线程
		
		 Socket socket=new Socket("localhost", 10086);
		 System.out.println(socket.getLocalAddress().getHostName()+"_"+socket.getLocalPort()+"加入聊天了!!!");
		 new ClientInThread(socket).start();
		 new ClientOutThread(socket).start();
	}
}
class ClientOutThread extends Thread{
	Socket socket;
	
	public ClientOutThread(Socket socket) {
		this.socket = socket;
	}

	public void run(){
		try{
			BufferedWriter bout=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
			BufferedReader bin=new BufferedReader(new InputStreamReader(System.in));
			while(true){
				String line=bin.readLine();
				bout.write(line);
				bout.flush();
				if(line.endsWith("886")){
					socket.shutdownOutput();
				}
			}
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}
}
class ClientInThread extends Thread{
	Socket socket;
	public ClientInThread(Socket socket) {
		this.socket = socket;
	}
	public void run(){
		try{
			InputStream in=socket.getInputStream();
			while(true){
				  byte[] arr=new byte[1024];
				  int n=in.read(arr);
				  System.out.println(socket.getLocalAddress().getHostName()+"_"+
				  socket.getLocalPort()+
				  "接收到信息:"+new String(arr,0,n));
			}
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}
}

  • 服务器端
package com.zhiyou100.day14_socket;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class Demo06ChatServer {
    public static ArrayList<Socket> socketList=new ArrayList<>();
	public static void main(String[] args)throws Exception {
		//群聊:服务器端:1 需要时刻等待连接 2 接收到的所有信息 必须给所有连接再发送一边
		ServerSocket ss=new ServerSocket(10086);
		while(true){
			Socket socket=ss.accept();
			socketList.add(socket);
			new ChatThread(socket).start();
			//System.out.println("main::"+socketList.size());
		}
	}
}
//2 创建一个线程:实现服务器端接受制定socket的信息  把信息发送给所有的socket
class ChatThread extends Thread{
	Socket socket;
	public ChatThread(Socket socket) {
		this.socket = socket;
	}
	public void run(){
		try{
			  //获取当前socket的输入流
			  InputStream in=socket.getInputStream();
			  while(true){
				  byte[] arr=new byte[1024];
				  int n=in.read(arr);
				  String message=new String(arr,0,n);
				  message=socket.getInetAddress().getHostName()+"_"+socket.getPort()+"说:"+message;
				  //System.out.println(socket.getPort()+"::"+Demo06ChatServer.socketList.size());
				  //把arr中读取的信息写道所有的socket的输出流中
				  for (int i = 0; i <Demo06ChatServer.socketList.size(); i++) {
					   OutputStream out=Demo06ChatServer.socketList.get(i).getOutputStream();
					   out.write(message.getBytes());
				  }
			  }
		}catch(Exception e){throw new RuntimeException(e);}
	}
}

6 内部类

A类定义在B类中 ,A类就是B类的内部类
如果A类的存在依赖B类的存在而存在时  可以把A类定义为B类的内部类

内部类1:成员内部类

内部类是外部类的实例成员
package com.zhiyou100.day14_socket;

public class Demo07Inner {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Outer07.Inner07 i1;//定义引用
		i1=new Outer07().new Inner07();//创建内部类对象 需要通过外部类对象来创建
		Outer07 o1=new Outer07();
		i1=o1.new Inner07();
		i1.test();
	}

}
class Outer07{
	String name="外部类name";
	class Inner07{
		String name="内部类name";
		public void test(){
			String name="局部变量name";
			System.out.println("name="+name);
			System.out.println("this.name="+this.name);
			System.out.println("Outer07.this.name="+Outer07.this.name);
		}
	}
}

内部类2:静态内部类

内部类是外部类的静态成员
package com.zhiyou100.day14_socket;

public class Demo08Inner {
  public static void main(String[] args) {
	  Outer08.Inner08 i1;//定义引用
	  i1=new Outer08.Inner08();//创建对象
  }
}
class Outer08{
	int a=1;
	static int b=2;
	static class Inner08{
		int c=1;
		void hehe(){
			System.out.println("c="+c);
			//System.out.println("a="+a); 静态内部类不能访问外部类的实例成员
			System.out.println("b="+b);
		}
	}
}

内部类3:局部内部类

内部类定义在代码块或者方法中
package com.zhiyou100.day14_socket;

public class Demo09Inner {
    //局部内部类:定义在方法或者代码块中
	public static void main(String[] args) {
	}
}
class Outer09{
	{
		class Inner091{}
		Inner091 i1=new Inner091();//局部内部类  只能再当前大括号内使用
	}
	void show(){
		class Inner091{
		}
		Inner091 i1=new Inner091();//局部内部类  只能再当前大括号内使用
	}
}

内部类4:匿名内部类

没有名字的局部内部类
package com.zhiyou100.day14_socket;

import java.util.concurrent.FutureTask;

public class Demo10Inner {
	public static void main(String[] args) {
		  //想使用Fu的hehe方法
		  //方式1:定义子类 创建子类对象 通过子类对象调用方法即可
		  new Zi1().hehe();
		  
		  //方式2:
		  //:如果此子类的对象只创建一个  可以使用匿名内部类实现 方法的调用
		  Fu fu=new Fu() {
			    void show() {}
		  };
		  fu=new Fu() {
				void show() {}
		  };
		  fu=new Fu() {
				void show() {}
		  };
	}
}
class Zi1 extends Fu{
	void show() {}
}
abstract class Fu{
	void hehe(){}
	abstract void show();
}

posted @ 2021-09-09 22:52  RenVei  阅读(27)  评论(0编辑  收藏  举报