Java学习总结2——网络编程

735 阅读8分钟

Java网络编程

一、构造ip地址:

InetAddress ip = InetAddress.getByName(host);//host可以是计算机名字也可以是IP地址如127.0.0.1

二、Socket套接字

在程序中使用scoket进行通信,使用socket通信需要指定IP、端口、协议(UDP、TCP);数据发送分为两步:1、第一步是监听(等待数据发送过来),用来接收数据,需指定监听的端口;2、第二部是发送(需要指定发送到哪个计算机:IP地址,该计算机的哪个程序:Port号)。

socket中分为发送端和接收端:发送端一般为客户端,接收端一般为服务端。

一般有多个客户端,一个服务端。

三、使用UDP协议

UDP协议无需建立连接,直接向接收端发送数据报,不用考虑对方是否接收到数据报,只需要向接收方发送就行,至于接收方有没有接收到发送端不用管。所以使用UDP协议进行网络数据传输是不可靠的,但是速度快!

使用UDP协议开发发送端: 用DatagramSocket发送数据:

DatagramSocket ds = new DatagramSocket();//socket套接字

用DatagramPacket作为包裹(发送的数据内容):

byte[] buf = "你好,我想给你发送数据!".getBytes();//字节数组
int length = buf.length;//发送的长度
InetAddress address = InetAddress.getByName("127.0.0.1");//指定接收端的IP地址
int port = 7878;//指定接收端的监听端口号,与接收端对应

DatagramPacket dp = new DatagramPacket(buf, length, address, port);//待发送的包裹

send()发送数据,close()释放资源。

ds.send(dp);//发送1次
//ds.send(dp);//发送2次
...
//ds.send(dp);//发送n次
ds.close();//发送完毕,释放资源

举个栗子🌰:

//UDP发送端
public class Demo2_UDP_Send {
	public static void main(String[] args) throws Exception {
		DatagramSocket ds = new DatagramSocket();//socket套接字
		
		byte[] buf = "你好,我想给你发送数据!".getBytes();//字节数组
		int length = buf.length;//发送数据的长度
		InetAddress address = InetAddress.getByName("127.0.0.1");//指定接收端的IP地址
		int port = 7878;//指定接收端的端口号
		
		DatagramPacket dp = new DatagramPacket(buf, length, address, port);//待发送的包裹
		
		ds.send(dp);//发送
		ds.close();//发送完毕,释放资源
	}
}

使用UDP协议开发接收端: 用DatagramSocket来监听发送端发送过来的数据:

DatagramSocket ds = new DatagramSocket(7878);//接收端的监听端口

用DatagramPacket作为接收数据的容器:

byte[] buf = new byte[1024];
int length = buf.length;
DatagramPacket dp = new DatagramPacket(buf, length);//直接作为接收数据的容器

receive()接收数据,程序会在这里等待数据的到来:

ds.receive(dp);//等待数据到来

与发送端一样,接收到数据之后同样需要释放对象ds的资源:

ds.close();//接收到数据,释放资源

举个栗子🌰:

//UDP接收端
public class Demo3_UDP_Receive {
	public static void main(String[] args) throws Exception {
		DatagramSocket ds = new DatagramSocket(7878);//接收端的监听端口
		
		byte[] buf = new byte[1024];
		int length = buf.length;
		DatagramPacket dp = new DatagramPacket(buf, length);//直接作为接收数据的容器
		
		ds.receive(dp);//等待数据到来
		
		String str = new String(dp.getData(), 0, dp.getLength());
		System.out.println(str);//输出发送过来的数据
		
		ds.close();//接收到数据,释放资源
 	}
}

程序运行结果:

接收端的其他信息获取:

dp.getAddress();//获取发送端的IP地址
dp.getPort();//获取发送端的端口号

使用UDP协议实现两个用户双向聊天:

1、新建一个SendThread发送线程类:

public class SendThread extends Thread {
	
	private int port;
	public SendThread(int port) {
		this.port=port;
	}
	
	@Override
	public void run() {
		DatagramSocket ds=null;
		try {
			ds = new DatagramSocket();
			Scanner inputstr = new Scanner(System.in);//输入数据
			
			while (true) {
				String str = inputstr.nextLine();
				if (str.equals("end")) break;
				byte[] buf = str.getBytes();//字节数组
				int length = buf.length;//发送数据的长度
				InetAddress address = InetAddress.getByName("127.0.0.1");//指定接收端的IP地址
				//int port = 7878;//指定接收端的端口号
				
				DatagramPacket dp = new DatagramPacket(buf, length, address, port);//发送包裹
				
				ds.send(dp);//发送
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (ds!=null) {//有数据传输,所以需要释放资源
				ds.close();
			}
		}
		
		
	}
}

2、再建一个ReceiveThread接收线程类:

public class ReceiveThread extends Thread {
	
	private int port;
	public ReceiveThread(int port) {
		this.port=port;
	}
	
	@Override
	public void run() {
		DatagramSocket ds=null;
		try {
			ds = new DatagramSocket(port);//指定端口号来监听数据,与发送端发送数据包指定的端口相对应
			
			while (true) {
			    byte[] buf = new byte[1024];
			    int length = buf.length;
			    DatagramPacket dp = new DatagramPacket(buf, length);//作为接收数据的容器
			    ds.receive(dp);//等待数据到来
			    
			    String str = new String(dp.getData(), 0, dp.getLength());
			    System.out.println("收到来自端口"+dp.getPort()+"的消息:"+str);//输出发送过来的数据
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (ds!=null) {//有数据传输,所以需要释放资源
				ds.close();
			}
		}
	}
}

3、新建Chant_User01类(用户1):

public class Chant_User01 {
	public static void main(String[] args) {
		new SendThread(7878).start();//用户1的发送线程,7878端口为用户2的接收线程监听端口
		new ReceiveThread(7879).start();//用户1的接收线程,7879监听来自用户2发送的数据
	}
}

4、新建Chant_User02类(用户2):

public class Chant_User02 {
	public static void main(String[] args) {
		new ReceiveThread(7878).start();//用户2的接收线程,7878监听来自用户1发送的数据
		new SendThread(7879).start();//用户2的发送线程,7879端口为用户1的接收线程监听端口
	}
}

实现效果:

用户1:

用户1

用户2:

用户2

四、使用TCP协议

TCP协议需要通过三次握手建立连接,客户端与服务端之间是一个双向通道,既可以发送数据(使用输出流),也可以接收数据(使用输入流)。所以使用TCP协议进行网络数据传输是可靠的,但是速度较慢!

使用TCP协议开发客户端: 客户端直接使用Socket,使用输出流OutputStream写入数据发送:

//TCP直接使用Socket
Socket s = new Socket("127.0.0.1", 8888);//与TCP接收端建立连接
//使用输出流来传输数据
OutputStream output = s.getOutputStream();
output.write("ww.baidu.com".getBytes());//向服务端写入数据
s.close();

使用TCP协议开发服务端: 服务端使用ServerSocket,accept()等待接收客户端发送的TCP连接请求,与客户端创建连接成功之后会返回一个socket对象,socket对象可以创建输入流InputStream接收客户端发送的数据,也可以创建输出流OutputStream发送数据。

ServerSocket ss = new ServerSocket(8888);//指定服务端监听端口
		
Socket client = ss.accept();//等待连接,建立与客户端的连接
		
InputStream input = client.getInputStream();//使用输入流来接收数据

byte[] buf = new byte[1024];
int length = input.read(buf);//等待客户端发送数据

client.close();//关闭连接
ss.close();

使用TCP协议实现两端双向聊天功能:

1、新建TCP_Client客户端类:

//TCP客户端
public class TCP_Client {
	public static void main(String[] args) throws Exception {
		Socket s = new Socket("127.0.0.1", 8888);//与Server端建立连接
		
		OutputStream output = s.getOutputStream();//使用输出流来发送数据
		InputStream input = s.getInputStream();//使用输入流接收来自Server的数据
		
		/**
		 * 匿名内部类创建一个线程来接收数据
		 * */
		new Thread() {
			public void run() {
				byte[] buf = new byte[1024];//字节数组容器
				int length = -1;
				try {
					while ((length = input.read(buf))!=-1) {//等待服务端发送数据
						System.out.println(new String(buf, 0, length));
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}.start();
		
		/**
		 * 发送数据
		 * */
		Scanner scanner = new Scanner(System.in);
		while (true) {
			String in_str = scanner.nextLine();
			if (in_str.equals("end"))break;
			output.write(in_str.getBytes());//向Server端写入数据
		}
		
		s.close();//关闭连接
	}
}

1、新建TCP_Server服务端类:

//TCP连接的服务端
public class TCP_Server {
	public static void main(String[] args) throws Exception {
		ServerSocket ss = new ServerSocket(8888);//指定服务端监听端口
		
		Socket client = ss.accept();//等待连接,建立与客户端的连接
		System.out.println("客户端已连接进来!");
		
		InputStream input = client.getInputStream();//使用输入流来接收数据
		OutputStream output = client.getOutputStream();//使用输出流发送数据
		
		/**
		 * 匿名内部类创建一个线程来发送数据
		 * */
		new Thread() {
			public void run() {
				Scanner scanner = new Scanner(System.in);
				while (true) {
					String str = scanner.nextLine();
					if (str.equals("end"))break;
					try {
						output.write(str.getBytes());//向客户端写入数据
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		/**
		 * 接收数据
		 * */
		byte[] buf = new byte[1024];
		int length = -1;
		while ((length = input.read(buf))!=-1) {//等待客户端发送数据
			System.out.println(new String(buf, 0, length));
		}
		
		client.close();//关闭与客户端的连接
		ss.close();//关闭监听
	}
}

运行结果:

客户端:

客户端

服务端:

服务端

多个客户端发送数据,一个服务端接收数据:

1、新建TCP_Server_Many类,可以接收多个客户端连接的TCP服务端和处理多个客户端的数据:

public class TCP_Server_Many {
	public static void main(String[] args) {
		new VerbClientConnect().start();//启动服务端监听线程监听多个客户端的连接
	}
}

//监听多个客户端的连接
class VerbClientConnect extends Thread {
	@Override
	public void run() {
		try {
			ServerSocket serverSocket = new ServerSocket(8888);
			int i=0; 
			while (true) {
				Socket socket = serverSocket.accept();//等待请求连接
				i++;
				System.out.println("接收到一个客户端的连接:Client"+i+socket.getInetAddress());
				new ClientMessage(socket,i).start();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

//处理客户端发送的消息
class ClientMessage extends Thread {
	
	private Socket socket;
	private int i;
	
	public ClientMessage(Socket socket, int i) {
		this.socket=socket;
		this.i=i;
	}

	@Override
	public void run() {
		try {
			InputStream input = socket.getInputStream();//使用输入流来接收数据
			byte[] buf = new byte[1024];
			int length = -1;
			while ((length = input.read(buf))!=-1) {//等待客户端发送数据
				System.out.println("来自客户端Client"+i+"的消息:"+new String(buf, 0, length));
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (socket!=null) {
				try {
					socket.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

2、新建TCP_Client_Many类,可以发送多条数据的TCP客户端:

public class TCP_Client_Many {
	public static void main(String[] args) throws Exception {
		Socket socket = new Socket("127.0.0.1", 8888);//请求连接
		OutputStream output = socket.getOutputStream();//使用输出流来发送数据
		Scanner scanner = new Scanner(System.in);
		while (true) {
			String str = scanner.nextLine();
			if (str.equals("end"))break;
			output.write(str.getBytes());//向服务端发送数据
		}
		socket.close();
	}
}

运行效果:

Client1:

Client2:

Client3:

服务端:

今日寄语:

种一棵树最好的时机是十年前,其次是现在!

欢迎关注个人微信公众号:桃李报春