java之网络编程

1、类

a. InetSocketAddress

  • 此类实现 IP 套接字地址(IP 地址 + 端口号)。
  • 继承 java.net.SocketAddress

a.a 构造方法

InetSocketAddress(InetAddress addr, int port) 
         // 根据 IP 地址和端口号创建套接字地址。 
InetSocketAddress(int port)  // 一般作为接收端 
         // 创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值。 
InetSocketAddress(String hostname, int port) 
         // 根据主机名和端口号创建套接字地址。 

a.b方法

 InetAddress getAddress() 
        // 获取 InetAddress。 
 String getHostName() 
         // 获取 hostname。 
 int getPort() 
        //  获取端口号。 

b. java.net.InetAddress

此类表示互联网协议 (IP) 地址。

c. DatagramPacket

c.a构造方法

DatagramPacket(byte[] buf, int length) 
      //    构造 DatagramPacket,用来接收长度为 length 的数据包。 
DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
      //    构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。 
DatagramPacket(byte[] buf, int length, SocketAddress address) 
       //   构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。 

c.b 方法

// get 方法
InetAddress getAddress() 
      //    返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。 
 byte[] getData() 
      //    返回数据缓冲区。 
 int getLength() 
      //    返回将要发送或接收到的数据的长度。 
 int getPort() 
       //   返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。 
 SocketAddress getSocketAddress() 
        //  获取要将此包发送到的或发出此数据报的远程主机的 SocketAddress(通常为 IP 地址 + 端口号)。 


// set 方法
 void setAddress(InetAddress iaddr) 
   // 设置要将此数据报发往的那台机器的 IP 地址。 
    
 void setData(byte[] buf) 
        //  为此包设置数据缓冲区。 
 void setData(byte[] buf, int offset, int length) 
        //  为此包设置数据缓冲区。 
 void setLength(int length) 
         // 为此包设置长度。 
 void setPort(int iport) 
        //  设置要将此数据报发往的远程主机上的端口号。 
 void setSocketAddress(SocketAddress address) 
        //  设置要将此数据报发往的远程主机的 SocketAddress(通常为 IP 地址 + 端口号)。 

d.DatagramSocket

d.a构造方法

  DatagramSocket() 
        //  构造数据报套接字并将其绑定到本地主机上任何可用的端口。 	
  DatagramSocket(int port) 
        //  创建数据报套接字并将其绑定到本地主机上的指定端口。 
  DatagramSocket(int port, InetAddress laddr) 
       //   创建数据报套接字,将其绑定到指定的本地地址。 
  DatagramSocket(SocketAddress bindaddr) 
       //   创建数据报套接字,将其绑定到指定的本地套接字地址。 

d.b方法

void bind(SocketAddress addr) 
      //    将此 DatagramSocket 绑定到特定的地址和端口。 
 void close() 
      //    关闭此数据报套接字。 
 void connect(InetAddress address, int port) 
       //   将套接字连接到此套接字的远程地址。 
 void connect(SocketAddress addr) 
       //   将此套接字连接到远程套接字地址(IP 地址 + 端口号)。 
 void disconnect() 
       //   断开套接字的连接。 
 int getPort() 
      //    返回此套接字的端口。 
    
     //     接收和发送方法
    
 void receive(DatagramPacket p) 
      //    从此套接字接收数据报包。 
 void send(DatagramPacket p) 
      //    从此套接字发送数据报包。 

e.ServerSocket

e.a 构造方法

ServerSocket() 
          // 创建非绑定服务器套接字。 
ServerSocket(int port) 
         // 创建绑定到特定端口的服务器套接字。 

e.b 方法

Socket accept() 
      //    侦听并接受到此套接字的连接。 
 void bind(SocketAddress endpoint) 
      //    将 ServerSocket 绑定到特定地址(IP 地址和端口号)。 
 void bind(SocketAddress endpoint, int backlog) 
      //    将 ServerSocket 绑定到特定地址(IP 地址和端口号)。 
 void close() 
      //    关闭此套接字。 

f.Socket

此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。

f.a构造方法

  Socket() 
        //  通过系统默认类型的 SocketImpl 创建未连接套接字 
  Socket(InetAddress address, int port) 
       //   创建一个流套接字并将其连接到指定 IP 地址的指定端口号。 

f.b方法

 void bind(SocketAddress bindpoint) 
     //     将套接字绑定到本地地址。 
 void close() 
     //     关闭此套接字。 
 InputStream getInputStream() 
      //    返回此套接字的输入流。 
 OutputStream getOutputStream() 
     //     返回此套接字的输出流。 
 int getPort() 
      //    返回此套接字连接到的远程端口。 
 InetAddress getInetAddress() 
      //    返回套接字连接的地址。 
 

2、UDP 案例

a.服务端

public class ServerSocket {
	
	// 服务器端

	public static void main(String[] args) throws IOException {
		
		// 服务端,指明主机即可,默认的 ip 127.0.0.1
		DatagramSocket server = new DatagramSocket(8888);
		
		DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
		// 构成死循环,一直会监听发送过来的程序
		while(true) {
			// 将接受到的数据放到 packet 中 
			server.receive(packet); 		
			
			byte[] data = packet.getData();
			int length = packet.getLength();
			int port = packet.getPort();
			InetAddress address = packet.getAddress();
			System.out.println("接受来自 :  "+address.getHostName()+" "+port+"  的数据!");
			System.out.println(new String(data,0,length));
			
		}
	}
}

b. 客户端

public class ClientSocket {
	
	public static void main(String[] args) throws IOException {
		
		// 客户端,发送数据的一方
		String ip = "localhost";
        InetAddress addr = InetAddress.getByName("127.0.0.1");
		DatagramSocket sendSocket =  new DatagramSocket(8889, addr);
		
		Scanner sc = new Scanner(System.in);
		
		while(true) {
			
			String str = sc.nextLine();
			if("quit".equals(str)) {
				break;
			}
			// 设置数据报
			DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
			
			// 构造数据包 
			// 将数据 set 到数据包里 
			packet.setData(str.getBytes());
            // 通过 InetAddress.getByName("127.0.0.1) 方式返回一个InetAddress对象
          //   new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666);
			packet.setSocketAddress(new InetSocketAddress("localhost",8888));
			
			// 发送数据 
			sendSocket.send(packet);
			
		}
	}
}

3、TCP案例

https://blog.csdn.net/qq_26525215/article/details/51362924

3.1单向通讯

客户机 -》 服务器

a.服务端

public class LoginServer {

	public static void main(String[] args) throws Exception {
		
		
		System.out.println("这里是 LogingServer");
		
		// 创建服务端的 socket
		ServerSocket server = new ServerSocket(8888);
		
		// 监听传送过来的 socket ,如果没有就会阻塞 
		Socket socket = server.accept();
		
		// 接受来自客户端的数据 
		InputStream in = socket.getInputStream();
		
		DataInputStream dis = new DataInputStream(in);
		
		System.out.println(dis.readUTF());
		
		dis.close();
		in.close();
		socket.close();
		server.close();
		
	}
	
}

b.客户端

public class LoginClient {
	
	public static void main(String[] args) throws Exception {
		
		System.out.println("这里是 LogingClient");
		// 创建 socket ,同时指定连接的 ip 和端口 
		Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
		
		// 得到输出流,用于向服务器发送数据
		OutputStream out = socket.getOutputStream();
		
		DataOutputStream dos = new DataOutputStream(out);
		
		dos.writeUTF("hello , I'm bigguy!");
		
		dos.close();
		out.close();
		socket.close();
	}

}

3.2双向通讯

a.服务端

public class LoginServer {

	public static void main(String[] args) throws Exception {
		
		
		System.out.println("这里是 LogingServer");
		
		// 创建服务端的 socket
		ServerSocket server = new ServerSocket(8888);
		
		// 监听传送过来的 socket ,如果没有就会阻塞 
		Socket socket = server.accept();
		
		// 接受来自客户端的数据 
		InputStream in = socket.getInputStream();
		
		DataInputStream dis = new DataInputStream(in);
		
		System.out.println(dis.readUTF());
		
		OutputStream outputStream = socket.getOutputStream();
		DataOutputStream dos = new DataOutputStream(outputStream);
		
		dos.writeUTF("你好,登入成功");
		
		
		dis.close();
		outputStream.close();
		dos.close();
		in.close();
		socket.close();
		server.close();
	}
}

b.客户端

public class LoginClient {
	
	public static void main(String[] args) throws Exception {
		
		
		System.out.println("这里是 LogingClient");
		Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
		
		OutputStream out = socket.getOutputStream();
		
		DataOutputStream dos = new DataOutputStream(out);
		
		dos.writeUTF("hello , I'm bigguy!");
		
		// 得到网络中的输入流 
		InputStream in = socket.getInputStream();
		
		DataInputStream dis = new DataInputStream(in);
		System.out.println(dis.readUTF());
		
		dos.close();
		in.close();
		dis.close();
		out.close();
		socket.close();
	}
}

c.注意

  • 服务端
    • 服务端创建 ServerSocket ,在指定的端口监听并处理请求
    • ServerSocket 通过 accept() 接受用户请求并返回对应的 Socket ,如果没有请求一直会处理阻塞的状态(程序一直运行),线程被阻塞
  • 客户端
    • 客户端创建 Socket , 需要指定服务端器的 ip 和 端口号,向服务端发送和接受响应
  • 一但 socket建立网络连接后,通讯就和普通的IO操作一样
  • 输入/输出流
    • 建议使用 DataOutputStream 和 DataInputStream 和平台无关
    • 对象流可以使用 ObjectInputStream / ObjectOutputStream
    • 如果是字符串通信,可以使用 BufferdReader / PrintWriter

3.3服务端持续监听

a.客户端

public class LoginClient {
	
	public static void main(String[] args) throws Exception {
		
		Scanner sc = new Scanner(System.in);
		
		System.out.println("这里是 LogingClient");
		Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
		
		System.out.println("请输入用户名和密码 : ");
		
		String name = sc.next();
		String password = sc.next();
		
		User user = new User(name,password);
	
        // 序列化对象,对象必须实现序列化接口 
		ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
		oos.writeObject(user);
		
		// 得到网络中的输入流 
		InputStream in = socket.getInputStream();
		
		DataInputStream dis = new DataInputStream(in);
		System.out.println(dis.readUTF());
		
		in.close();
		dis.close();
		oos.close();
		socket.close();
	}
}

b.服务端

public class LoginServer {

	public static void main(String[] args) throws Exception {
		
		
		System.out.println("这里是 LogingServer");
		
		// 创建服务端的 socket
		ServerSocket server = new ServerSocket(8888);
		
		// 使服务端一直的运行(一直监听)
		while(true) {
			
			// 监听传送过来的 socket ,如果没有就会阻塞 
			Socket socket = server.accept();
			// 接受来自客户端的数据 
			
			ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
			Object user = ois.readObject();
			User realUser = null;
			if( user!=null && user instanceof User) {
				realUser = (User)user;
			}else {
				throw new Exception("不能转化为 User 对象");
			}
			
			System.out.println("你好 : "+realUser.getName()+", 你的密码是 : "+realUser.getPassword());
			OutputStream outputStream = socket.getOutputStream();
			DataOutputStream dos = new DataOutputStream(outputStream);
			dos.writeUTF("你好,登入成功");
			
			outputStream.close();
			dos.close();
			socket.close();
		}
		
		// 产生了 死循环,不用关闭 serverSocket 了 
		
	}
}

c.POJO类

public class User implements Serializable{
	// 使用对象流,对象必须序列化 
	private String name;
	private String password;
    .....
}

3.4多线程方式

  • 3.3 的问题,当多个 socket 同时访问时候,服务端只能一个一个的处理,效率降低
  • 考虑将处理socket 的任务作出多线程,并发处理 -> 提高效率
  • 还可以将线程放在线程池中,减少创建一个线程的开销

a.服务端

public class LoginServer {

	public static void main(String[] args) throws Exception {
		
		
		System.out.println("这里是 LogingServer");
		
		// 创建服务端的 socket
		ServerSocket server = new ServerSocket(8888);
		
		// 使服务端一直的运行(一直监听)
		while(true) {
			
			// 监听传送过来的 socket ,如果没有就会阻塞 
			Socket socket = server.accept();
			// 接受来自客户端的数据 
			
			LoginThread sonTask = new LoginThread(socket);
			new Thread(sonTask).start(); 	// 开启线程 
			
		}
		
		// 产生了 死循环,不用关闭 serverSocket 了 
	}
}

b.客户端

public class LoginClient {
	
	public static void main(String[] args) throws Exception {
		
		Scanner sc = new Scanner(System.in);
		
		System.out.println("这里是 LogingClient");
		Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
		
		System.out.println("请输入用户名和密码 : ");
		
		String name = sc.next();
		String password = sc.next();
		
		User user = new User(name,password);

		ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
		oos.writeObject(user);
		
		// 得到网络中的输入流 
		InputStream in = socket.getInputStream();
		
		DataInputStream dis = new DataInputStream(in);
		System.out.println(dis.readUTF());
		
		in.close();
		dis.close();
		oos.close();
		socket.close();
	}
}

c.线程类

public class LoginThread implements Runnable{

	Socket socket = null;
	
	public LoginThread(Socket socket) {
		this.socket = socket;
	}
	
	public LoginThread() {
		
	}
	
	public void run() {
		
		ObjectInputStream ois =null;
		OutputStream outputStream = null;
		DataOutputStream dos = null;
		try {
			ois = new ObjectInputStream(socket.getInputStream());
			
			Object user = ois.readObject();
			User realUser = null;
			
			if( user!=null && user instanceof User) {
				realUser = (User)user;
			}else {
				try {
					throw new Exception("不能转化为 User 对象");
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			
			System.out.println("你好 : "+realUser.getName()+", 你的密码是 : "+realUser.getPassword());
			outputStream = socket.getOutputStream();
			dos = new DataOutputStream(outputStream);
			dos.writeUTF("你好,登入成功");
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e1) {
			e1.printStackTrace();
		}finally {
            // 关闭资源
			try {
				if(outputStream!=null) {
					outputStream.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if(outputStream!=null) {
					dos.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if(outputStream!=null) {
					socket.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

4.网络传输文件

a.客户端

将文件读到网络中的输出流中

public class FileClient {

	public static void main(String[] args) throws Exception{
		// 文件传输方,将文件发送给服务器端
		
		Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 8888);
		
		OutputStream outputStream = socket.getOutputStream();
		String file = "C:\\Users\\Administrator\\Desktop\\文档总结\\视频文档\\javase\\网络编程.md";
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
		
		int len = 0;
		
		while((len=bis.read())!=-1) {
			outputStream.write(len);
		}
		
		bis.close();
		outputStream.close();
		socket.close();
		
	}	
}

b.服务端

将文件从传过来的套接字中读出来,写到本地

public class FileServer {

	public static void main(String[] args) throws Exception {
		
		ServerSocket server = new ServerSocket(8888);
		
		Socket socket = server.accept();
		
		InputStream inputStream = socket.getInputStream();
		OutputStream outputStream = socket.getOutputStream();
		
		// 客户端传过来的的流文件
		
		BufferedInputStream bis  = new BufferedInputStream(inputStream);
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("./demo.md"));
		int len = 0;
		while((len=bis.read()) !=-1) {
			bos.write(len);
		}
		
		bos.close();
		bis.close();
		
		server.close();
		
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值