网络编程(1)——基础知识讲解

在这篇博文中,本人以展示网络编程的例子来为本人之后的博文做一下铺垫,同学们在学习这篇博文的时候,建议还是抱着和学习本人之前的博文——《XML 解析》《Properties 解析》一样的态度——学习套路的方式学习这篇博文。因为本人将在之后的博文中同样地做出一个“工具”,来省略这里的步骤。那么,话不多说,开始我们这篇博文的学习吧:

那么,本人先来展示一下一个服务器 和 一个 客户之间的连接的代码:
首先,为了之后的代码方便编写,本人现来给出一个接口:

package com.mec.about_net.core;

public interface IMecNet {
	int DEFAULT_PORT = 54188;
}

接下来就是 服务器 的代码:

package com.mec.about_net.server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import com.mec.about_net.core.IMecNet;

public class SimpleServer {
	private ServerSocket server;
	private int port;
	private DataInputStream dis;
	private DataOutputStream dos;
	
	public SimpleServer() {
		this.port = IMecNet.DEFAULT_PORT;
	}

	public SimpleServer setPort(int port) {
		this.port = port;
		return this;
	}
	
	public void startup() {
		try {
			System.out.println("开始建立服务器……");
			server = new ServerSocket(port);										// 1.创建服务器
			System.out.println("服务器建立成功!");
			System.out.println("开始侦听客户端连接请求……");
			Socket client = server.accept();										// 2.服务器等待客户端的响应,若无响应,则等待至有响应
			
			String clientIp = client.getInetAddress().getHostAddress();
			System.out.println("侦听到来自[" + clientIp + "]的连接请求,并成功连接!");
			
			System.out.println("开始建立与客户端的通信信道……");
			dis = new DataInputStream(client.getInputStream());		// 3.构建输入、输出流
			dos = new DataOutputStream(client.getOutputStream());
			System.out.println("已建立与客户端的通信信道!");
			
			System.out.println("开始侦听客户端发送来的信息……");
			String message = dis.readUTF();										// 4.从客户端读取信息;向客户端发出信息
			System.out.println("来自客户端的消息:[" + message + "]");
			dos.writeUTF("[" + message + "]");
			
			close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void close() {
		try {
			dis.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			dos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			server.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}

相应地,本人来给出一个这个类的Test类:

package com.mec.about_net.test;

import com.mec.about_net.server.SingleClientServer;

public class ServerTest {

	public static void main(String[] args) {
		new SimpleServer().startup();
	}

}

那么,我们来看一下运行结果:
在这里插入图片描述
可以看到,运行成功了,但是,右边的红色方块,表示还处于运行状态。
本人现在来解释一下:
由于我们现在没有创建客户端,所以,其实服务器一直处于运行下行语句的状态:

Socket client = server.accept();	

所以,产生了上图的结果。

那么,现在,本人来编写一个客户端的类:

package com.mec.about_net.client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

import com.mec.about_net.core.IMecNet;

public class SimpleClient {
	public static final String DEFAULT_IP = "127.0.0.1";	//这里的IP地址,就是本机的IP地址
	
	private Socket socket;
	private String serverIp;
	private int serverPort;
	
	private DataInputStream dis;
	private DataOutputStream dos;
	
	public SimpleClient() {
		serverIp = DEFAULT_IP;
		serverPort = IMecNet.DEFAULT_PORT;	//和我们上面的服务器设定一样的端口,才能保证服务器和客户端的连接
	}

	public SimpleClient setServerIp(String serverIp) {
		this.serverIp = serverIp;
		return this;
	}

	public SimpleClient setServerPort(int serverPort) {
		this.serverPort = serverPort;
		return this;
	}
	
	public void connectToServer() {		//这个方法的作用是:使得客户端和服务器连接,这也是这个类的核心
		try {
			socket = new Socket(serverIp, serverPort);
			dis = new DataInputStream(socket.getInputStream());
			dos = new DataOutputStream(socket.getOutputStream());
			
			dos.writeUTF("你好!");	
			String message = dis.readUTF();
			System.out.println("来自服务器的消息:" + message);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		close();
	}
	
	private void close() {
		try {
			dis.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			dos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
}

在这里插入图片描述那么,上面的例子看起来还貌似还蛮简单的。
现在,本人来编写一个能够满足如下要求的程序:
只要客户端不发出“byebye”信息,服务器就一直从客户端处读取信息。
那么,本人还是先来编写服务器的类:

package com.mec.about_net.server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import com.mec.about_net.core.IMecNet;

public class SingleClientServer {
	private ServerSocket server;
	private int port;
	
	public SingleClientServer() {
		this.port = IMecNet.DEFAULT_PORT;
	}
	
	public SingleClientServer setPort(int port) {
		this.port = port;
		return this;
	}
	
	public void startup() {
		try {
			System.out.println("开始启动服务器……");
			server = new ServerSocket(port);
			System.out.println("服务器启动成功!\n开始侦听客户端连接请求……");
			
			Socket socket = server.accept();
			String clientIp = socket.getInetAddress().getHostAddress();
			System.out.println("侦听到一个客户端[" + clientIp + "]的连接请求,并已连接!");
			new Thread(new Communication(socket)).start();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	class Communication implements Runnable {
		private DataInputStream dis;
		private DataOutputStream dos;
		private volatile boolean goon;
		
		public Communication(Socket client) {
			try {
				this.dis = new DataInputStream(client.getInputStream());
				this.dos = new DataOutputStream(client.getOutputStream());
				
				this.goon = true;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		public void send(String message) {
			try {
				dos.writeUTF(message);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		@Override
		public void run() {
			String message = null;
			while (goon) {
				try {
					message = dis.readUTF();
					System.out.println("来自客户端的消息:" + message);
					if (message.equalsIgnoreCase("byebye")) {
						goon = false;
					} else {
						send("[" + message + "]");
					}
				} catch (IOException e) {
					if (goon == true) {
						System.out.println("客户端异常掉线!");
						goon = false;
					}
				}
			}
			close();
		}
		
		private void close() {	//这里是关闭这个线程的方法
			goon = false;
			try {
				if (dis != null) {
					dis.close();
				}
			} catch (IOException e) {
			} finally {
				dis = null;
			}
			
			try {
				if (dos != null) {
					dos.close();
				}
			} catch (IOException e) {
			} finally {
				dos = null;
			}
			
			try {
				if (server != null && !server.isClosed()) {
					server.close();
				}
			} catch (IOException e) {
			} finally {
				server = null;
			}
		}
		
	}
	
}

相应地,本人来给出服务器的Test类:

package com.mec.about_net.test;

import com.mec.about_net.server.SingleClientServer;

public class ServerTest {

	public static void main(String[] args) {
		new SingleClientServer().startup();
	}

}

现在,本人来给出客户端的类:

package com.mec.about_net.client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

import com.mec.about_net.core.IMecNet;

public class SingleClientClient {
	public static final String DEFAULT_IP = "127.0.0.1";
	
	private Socket socket;
	private String ip;
	private int port;
	
	public SingleClientClient() {
		this.ip = DEFAULT_IP;
		this.port = IMecNet.DEFAULT_PORT;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public void setPort(int port) {
		this.port = port;
	}
	
	public void connectToServer() {
		try {
			socket = new Socket(ip, port);
			Communication communication = new Communication(socket);
			new Thread(communication).start();
			
			Scanner in = new Scanner(System.in);
			String message = "";
			while (!message.equalsIgnoreCase("byebye")) {	//这里检查客户端发的消息是否为"byebye",若不是,则读取下次输入 并 向服务器发送
				message = in.next();
				communication.send(message);
			}
			communication.close();
			in.close();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	class Communication implements Runnable {
		private Socket socket;
		private DataInputStream dis;
		private DataOutputStream dos;
		private volatile boolean goon;
		
		public Communication(Socket socket) {
			try {
				dis = new DataInputStream(socket.getInputStream());
				dos = new DataOutputStream(socket.getOutputStream());
				goon = true;
				
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		public void send(String message) {
			try {
				dos.writeUTF(message);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		@Override
		public void run() {
			String message = null;
			while (goon) {
				try {
					message = dis.readUTF();
					System.out.println("来自服务器的消息:" + message);
				} catch (IOException e) {
					if (goon == true ) {
						System.out.println("服务器异常宕机!");
					}
					goon = false;
				}
			}
			close();
		}
		
		private void close() {	//这里是关闭这个线程的方法
			goon = false;
			try {
				if (dis != null) {
					dis.close();
				}
			} catch (IOException e) {
			} finally {
				dis = null;
			}
			
			try {
				if (dos != null) {
					dos.close();
				}
			} catch (IOException e) {
			} finally {
				dos = null;
			}
			
			try {
				if (socket != null && !socket.isClosed()) {
					socket.close();
				}
			} catch (IOException e) {
			} finally {
				socket = null;
			}
		}
		
	}
	
}

底下是这个类的Test类:

package com.mec.about_net.test;

import com.mec.about_net.client.SingleClientClient;

public class ClientTest {

	public static void main(String[] args) {
		SingleClientClient client = new SingleClientClient();
		client.connectToServer();
	}

}

在这里插入图片描述上图表示连接成功了。
在这里插入图片描述
在这里插入图片描述可以看到:当我们的客户端的线程向服务器发出消息时,服务器的线程会显示客户端发来的消息,并且给服务器发出回应。
在这里插入图片描述
上图可以看出,当我们的客户端向服务器发出“byebye”信息时,客户端正常关闭,并且在服务器这里显示客户端发来的消息,然后服务器正常关闭。
在这里插入图片描述上图展示的是当我们强制关闭服务器时,客户端的反应。

在这里插入图片描述上图展示的是当我们强制关闭客户端时,服务器的反应。

由于这篇博文是网络编程的基础,所以本人在这里就不进行深入的讲解了。
但是,本人之后的编程,将会大篇幅地用到这里的知识,所以,同学们不用担心这里的知识点讲得太浅。

那么,有关网络编程的基本知识点,在这里就讲解完毕了。
若是对上述知识点或代码有任何疑惑、意见或者建议,请在下方评论区提出,本人将尽早予以答复,觉得有所帮助的同学请留下小赞赞,谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值