一、多线程的TCP网络编程

  • 如果需要进行多次数据交互,就可以在程序中设置一个循环,不断向对方发送请求,即可完成多次数据交互。同样,如果需要让服务器同时响应多个客户端的请求,可以使用多线程的方法,也就是服务器端没接收到一个新的连接请求,就启动一个专门的线程与客户端进行交互。
  • 本测试程序可以分为三类:客户端类、服务器类和逻辑线程类
  1. 首先是客户端类
package com.bjpowernode.java_learning;

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

public class D127_1_ClientTest {
 public static void main(String[] args) {
  Scanner scanner = new Scanner(System.in);
  String input = null;
  Socket socket = null;
  DataInputStream in = null;
  DataOutputStream out = null;
  String serverIP = "127.0.0.1";                           //服务器端IP
  int port = 5050;
  
  try {
   socket = new Socket(serverIP,port);                  //连接服务器
   in = new DataInputStream(socket.getInputStream());   //创建输入流
   out = new DataOutputStream(socket.getOutputStream());//创建输出流
   System.out.println("请输入一个待计算的四则运算表达式");
   
   while(scanner.hasNext()) {
    input = scanner.nextLine();                       //从键盘输入一个待计算的四则运算表达式
    if(!input.contentEquals("0")) {
     out.writeUTF(input);                          //向服务器发送运算请求
     String result = in.readUTF();                 //等待读取运算结果
     System.out.println("服务器返回的计算结果:"+result);
     System.out.println("请输入一个正整数的四则运算表达式(输入0退出):");
     
    }else {
     break;                                        //请求结果
    }
   }
  }catch(Exception e) {
   System.out.println("与服务器连接中断");
  }finally {
   try {
    in.close();                                       //关闭网络连接
    out.close();
    socket.close();
    System.out.println("连接结束");
   }catch(Exception e) {
    
   }
  }
 }
}

 

 
  1. 接下来是服务器端类
package com.bjpowernode.java_learning;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import com.bjpowernode.java_learning.D127_3_ThreadTest;

public class D127_2_ServerTest {
 public static void main(String[] args) {
  ServerSocket server_socket = null;
  Socket socket = null;
  int port = 5050;
  
  while(true) {
   try {
    server_socket = new ServerSocket(port);
    System.out.println("服务器启动!");
   }catch(IOException e1) {
    System.out.println("正在监听");                   //ServerSocket对象不能重复创建
   }
   
   try {
    System.out.println("等待客户请求!");
    socket = server_socket.accept();
    System.out.println("客户的地址:"+socket.getInetAddress() + ":" + socket.getPort());
   }catch(IOException e) {
    System.out.println("正在等待客户"); 
   }
   
   if(socket!=null) {
    new D127_3_ThreadTest(socket);                          //为每个客户启动一个专门的线程
   }
  }
 }
}

 

 
  1. 最后是逻辑线程类
package com.bjpowernode.java_learning;

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

public class D127_3_ThreadTest extends Thread {
 Socket socket = null;
 DataInputStream in = null;
 DataOutputStream out = null;
 String str;
 String response;
 String ip;
 int port;
 
 public D127_3_ThreadTest(Socket socket) {
  this.socket = socket;
  start();
 }
 
 public void run() {
  try {
   in = new DataInputStream(socket.getInputStream());          //创建输入流
   out = new DataOutputStream(socket.getOutputStream());       //创建输出流
   ip = socket.getInetAddress().getHostAddress();              //客户端IP地址
   port = socket.getPort();                                    //客户端的端口号
   
   while(true) {
    str = in.readUTF();                                     //获取客户端的表达式
    System.out.println("客户端" + ip + ":" + port + "发送的请求内容:");
    System.out.println(str+"=?");
    
    if(str.contentEquals("0")) {
     System.out.println("连接结束");
     break;
    }else {
     response = doComputer(str);                         //对表达式进行计算
     out.writeUTF(response);                             //响应计算结果
    }   
   }  
  }catch(Exception e) {
   System.out.println("连接结束");
  }finally {
   try {
    in.close();
    out.close();
    socket.close();
   }catch(Exception e) {
    
   }
  }
 }
 public String doComputer(String str) {
  String input;
  String[] sym;
  String[] data;
  int a=0,b=0,result=0;
  input = str;
  data = input.split("\\D+");
  sym = input.split("\\d+");
  a = Integer.parseInt(data[0]);
  b = Integer.parseInt(data[1]);
  
  try {
   switch(sym[1]) {
   case "+":
    result = a + b;
    break;
   case "-":
    result = a - b;
    break;
   case "*":
    result = a * b;
    break;
   case "/":
    result = a / b;
   }
   System.out.println("计算结果:"+input+"="+result);
   return String.valueOf(result);
  }catch(java.lang.ArithmeticException e) {
   System.out.println("数据错误!");
   return "数据错误";
  }
 }

}

 

 
  1. 这样我们就做完了所有的工作,那么接下来进行启动该项目
  • 首先启动服务器的类,运行结果如下:
    127.1
  • 然后启动客户端类
    127.2
  • 我们在客户端类中cosole界面输入3*5然后回车
    127.3
  • 从上面的运行结果来看,得到了我们想要的结果,那么接下来输入0来结束这个项目的运行
    127.4

总结:在编写代码过程中我们遇到的问题,或者以前忘记的知识点:
1.服务器端类中:
(1)server_socket.accept() 一直处于阻塞直到接收了socket发来的请求,并返回一个socket对象;
(2)写一了一个多线程类,来给每个客户一个线程;
2.客户端类 \ (1)DataInputStream(socket.getInputStream()) \ socket的成员方法来获取输入流,并返回一个InputStream对象,然后经过java.io.DataInputStream方法转换为专有的流。
(2)DataOutputStream对象.writeUTF(String result) 用于传入字符串
(3)DataInputStream对象.readUTF() 用于读取字符串
3.多线程类
(1) 多线程重写了run方法
(2) 客户端和服务器端的读和写是正相反的。

二、源码:

    • D127_1_ClientTest.java
    • D127_2_ServerTest.java
    • D127_3_ThreadTest.java
    • https://github.com/ruigege66/Java/blob/master/D127_1_ClientTest.java
    • https://github.com/ruigege66/Java/blob/master/D127_2_ServerTest.java
    • https://github.com/ruigege66/Java/blob/master/D127_3_ThreadTest.java
    • CSDN:https://blog.csdn.net/weixin_44630050
    • 博客园:https://www.cnblogs.com/ruigege0000/
    • 欢迎关注微信公众号:傅里叶变换,个人账号,仅用于技术交流,后台回复“礼包”获取Java大数据学习视频礼包
    • 127.59
posted on 2020-07-05 13:07  心悦君兮君不知-睿  阅读(277)  评论(0编辑  收藏  举报