最近在学习Java的网络编程,特此记录一下学习成果。
先上图先,本代码是能正常运行的!!!!!!!!!!!
以上是代码的运行截图,使用两台虚拟机作为客户端,本机作为服务端进行通讯。服务端的干的活很简单,就是接收客户端的信息,然后把客户端的信息打上一个IP地址前缀返回给客户端!接下来的看看代码的实现吧!!!
public static void main(String[] args) throws Exception{
// 设置服务端就监听本机的某端口
ServerSocket server = new ServerSocket(10000);
System.out.println("服务端已启动");
// 服务端需要不停的监听客户端的连接,所以这里要写一个死循环
while (true){
// server.accept() 会堵塞主线程,直到收到客户端的连接才会继续下去
final Socket socket = server.accept();
String hostAddress = socket.getInetAddress().getHostAddress(); // 获取客户端的IP地址
System.out.println("["+hostAddress+"]已连接");
// 开启一个线程池,由于要实现与多客户端通讯,所以必须使用线程池
// 来一个客户就开一个线程专门为其服务
// 此时将会一个主线程(负责不断监听请求),和0~N个任务线程
ExecutorService service = Executors.newCachedThreadPool();
service.execute(()->{
receive(socket); // 提交线程任务
});
// 这个是为了实现客户端和服务端对话用
// 一个线程接收客户端信息,一个线程接收用户的输入,从而实现对话的
// 但是考虑到命令行下是单线程的,无法实现与多客户端对话,自己有懒得去写GUI,故嘿嘿..
// 取消注释能再命令行实现与单个客户端对话
// service.execute(()->{
// sender(socket);
// });
}
}
以上为服务端主线程的流程,下面是服务端的任务线程,我这边偷懒写成一个简单static方法,使用lamada调用,各位也可以写成一个Runable Class
private static void receive(Socket socket){
try {
InputStream inputStream = socket.getInputStream();
// 将客户端发来的信息装在BufferedReader中
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
String hostAddress = socket.getInetAddress().getHostAddress();
while (true){
// 判断客户端是否断开连接,比如在Linux上按 ctr+c 退出进程
if(socket.isClosed()){
System.out.println("["+socket.getInetAddress().getHostAddress()+"]已断开连接");
//break;
return; // 退出当前线程
}
// 读取客户端的来的信息,这儿会堵塞线程
String msg = reader.readLine();
String receiveMsg = ("["+hostAddress+"]:"+msg).toString().trim();
System.out.println(receiveMsg);
// 用PrintWriter装饰socket的OutputStream
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
// 给客户端发送信息
out.println(receiveMsg);
System.out.println("服务端:"+receiveMsg);
// 检测关键字
if(msg.equals("bye")){
System.out.println("["+socket.getInetAddress().getHostAddress()+"]再见");
return; // 退出当前线程
}
}
} catch (Exception e) {
if(socket.isClosed()){
System.out.println("["+socket.getInetAddress().getHostAddress()+"]socket关闭");
}
if(socket.isConnected()){
System.out.println("["+socket.getInetAddress().getHostAddress()+"]已断开连接");
}
return;
}
}
// private static void sender(Socket socket){
// try {
// System.out.println("服务端已启动,请输入");
// Scanner scanner = new Scanner(System.in);
// String msg = scanner.nextLine();
//
// PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
// while(true){
// out.println(msg);
// System.out.println("服务端:["+msg+"]");
// msg = scanner.nextLine();
// if(msg.equals("bye"))
// break;
// }
// }catch (Exception e){
// e.printStackTrace();
// }
// }
至此 服务端就写完了,接下来是客户端编程,客户端至少会有两个线程,一个是负责接收服务端的信息,一个负责给服务端发送信息,我这边是把这两个任务单独写成线程,主线程基本啥都没干、空跑,各位也可把其中上述的任一个任务写在主线程中:
// 客户端的主线程,就干了三件事
public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
// 1、创建TCP连接
final Socket socket = new Socket("192.168.0.142", 10000);
// 2、开启任务线程
ExecutorService service = Executors.newCachedThreadPool();
Future<Boolean> sender = service.submit(new Sender(socket));
Future<Boolean> receive = service.submit(new Receiver(socket));
// 3、关闭线程池,结束程式
if(!sender.get() && !receive.get()){
System.out.println("Sender Over");
System.out.println("Receive Over");
service.shutdown();
}
}
下面就是客户端的任务线程了,一个发送一个接收,这边是写成一个Callable类,为了能够判断这两个任务何时接收(return false),在主线中去获取到这个两个任务的返回值,然后关闭线程池,结束客户端进程
class Sender implements Callable<Boolean> {
private Socket socket = null;
public Sender(Socket socket){
this.socket = socket;
}
@Override
public Boolean call() throws Exception {
try{
System.out.println("客户端已启动,请输入");
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
boolean flag = true;
Scanner scanner = null;
while(flag){
scanner = new Scanner(System.in);
String msg = scanner.nextLine();
if(msg.equals("bye")){
out.println(msg);
flag = false;
}
out.println(msg);
System.out.println("客户端:["+msg+"]");
}
scanner.close();
return false;
}catch (Exception e){
e.printStackTrace();
return false;
}
}
}
// 这两个类的代码比较简单,大部分与服务端类似
class Receiver implements Callable<Boolean>{
private Socket socket = null;
public Receiver(Socket socket){
this.socket = socket;
}
@Override
public Boolean call() throws Exception {
try {
InputStream inputStream = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
boolean flag = true;
while (flag){
String msg = reader.readLine();
System.out.println("服务端:"+ msg);
if(msg.contains("bye")){
System.out.println("客户端收到byebye了");
flag = false;
}
}
inputStream.close();
reader.close();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
以上就是我这一天的学习成果,若有大佬看到,能不能给小弟指导指导。