疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java编程中网络编程之TCP协议


 

  

  一、TCP的基本概念

  TCP是专门设计用于在不可靠的英特网上提供可靠的、端到端的字节流通信的协议,是一个面向连接的协议,TCP连接是字节流而非报文流。UDP和TCP各有65536个端口号互不影响。

  二、单线程服务端

  以下代码只能实现服务端和客户端的同步对话。服务端处理完一个客户端请求,才会处理另一个客户端请求。服务器端的输出效果是Client1阻塞20秒,Client2不会执行。必须等Client1阻塞结束之后,Client2才会执行。该例子可用来学习TCP的基本语法。

  /**

  * TCP客户端1

  *

  * @author 徐越

  *

  */

  public class Client1

  {

  public static void main(String[] args) throws Exception

  {

  Socket socket = new Socket("127.0.0.1", 8821);

  OutputStream os = socket.getOutputStream();

  String msg = "我是徐越1";

  Thread.sleep(20000);

  os.write(msg.getBytes());

  os.flush();

  os.close();socket.close();

  }

  }

  /**

  * TCP客户端2

  *

  * @author 徐越

  *

  */

  public class Client2

  {

  public static void main(String[] args) throws Exception

  {

  Socket socket = new Socket("127.0.0.1", 8821);

  OutputStream os = socket.getOutputStream();

  String msg = "我是徐越2";

  os.write(msg.getBytes());

  os.flush();

  os.close();socket.close();

  }

  }

  /**

  * 单线程TCP服务端

  *

  * @author 徐越

  *

  */

  public class Server

  {

  public static void main(String[] args) throws Exception

  {

  // 创建端口为8821的TCP服务器端对象

  // 8821是服务器端的端口号而客户端从某端口A连到8821,端口A是随机的

  ServerSocket serverSocket = new ServerSocket(8821);

  while (true)

  {

  // 若无客户端发送请求则线程在此阻塞,方法不继续执行

  Socket socket = serverSocket.accept();

  System.out.println("connected");

  InputStream instream = socket.getInputStream();

  ByteArrayOutputStream bos = new ByteArrayOutputStream();

  int len = 0;

  byte[] buffer = new byte[1024];

  while ((len = instream.read(buffer)) != -1)

  {

  bos.write(buffer, 0, len);

  }

  instream.close();

  bos.flush();

  bos.close();

  String msg = bos.toString();

  System.out.println("客户端的IP:" + socket.getInetAddress()。getHostAddress());

  System.out.println("客户端的端口:" + socket.getPort());

  System.out.println("客户端的信息:" + msg);

  }

  }

  }

  执行结果

  connected

  客户端的IP:127.0.0.1

  客户端的端口:3775

  客户端的信息:我是小明1

  connected

  客户端的IP:127.0.0.1

  客户端的端口:3787

  客户端的信息:我是小明2

  三、多线程服务器

  在实际应用中是在服务器上运行一个永久的程序,接收来自其他多个客户端的请求,提供相应的服务。需要利用多线程实现多客户机制。服务器在指定的端口上监听是否有客户请求,一旦监听到就会启动一个专门的服务线程来响应该请求,而服务器本身在启动完线程之后马上又进入监听状态,等待下一个客户的到来。只要将服务端为如下代码,Client1和Client2就会异步执行。

  /**

  * 多线程服务端0

  *

  * @author 徐越

  *

  */

  public class MultiThreadServer0

  {

  // 端口号

  private int port = 8821;

  // 服务端

  private ServerSocket serverSocket;

  public MultiThreadServer0() throws IOException

  {

  // 创建服务器端

  serverSocket = new ServerSocket(port);

  System.out.println("服务器启动");

  }

  public void service()

  {

  while (true)

  {

  Socket socket = null;

  try

  {

  // 客户端进行连接时会触发accept方法从而建立连接

  socket = serverSocket.accept();

  new MultiThreadHandler(socket)。start();

  }

  catch (Exception e)

  {

  e.printStackTrace();

  }

  }

  }

  public static void main(String[] args) throws IOException

  {

  new MultiThreadServer1()。service();

  }

  }

  /**

  * 多线程处理类

  */

  class MultiThreadHandler extends Thread

  {

  private Socket socket;

  public MultiThreadHandler(Socket socket)

  {

  this.socket = socket;

  }

  private BufferedReader getReader(Socket socket) throws IOException

  {

  InputStream socketIn = socket.getInputStream();

  // InputStreamReader为转换流

  // InputStream本是字节流,现加一个Reader,表示用字符流的方式读取字节流

  InputStreamReader isr = new InputStreamReader(socketIn);

  return new BufferedReader(isr);

  }

  public void run()

  {

  try

  {

  BufferedReader br = getReader(socket);

  String msg = null;

  while ((msg = br.readLine()) != null)

  {

  System.out.println("客户端的IP:" + socket.getInetAddress()。getHostAddress());

  System.out.println("客户端的端口:" + socket.getPort());

  System.out.println("客户端的信息:" + msg);

  }

  }

  catch (IOException e)

  {

  e.printStackTrace();

  }

  finally

  {

  try

  {

  if (socket != null)

  {

  socket.close();

  }

  }

  catch (IOException e)

  {

  e.printStackTrace();

  }

  }

  }

  }

  /**

  * 多线程服务端1

  */

  public class MultiThreadServer1

  {

  // 端口号

  private int port = 8821;

  // 服务端

  private ServerSocket serverSocket;

  // 线程池

  private ExecutorService executorService;

  // 单个CPU线程池大小

  private final int POOL_SIZE = 10;

  public MultiThreadServer1() throws IOException

  {

  // 创建服务器端

  serverSocket = new ServerSocket(port);

  // 获取当前系统的CPU数目

  int cpuNums = Runtime.getRuntime()。availableProcessors();

  // 根据系统资源情况灵活定义线程池大小

  executorService = Executors.newFixedThreadPool(cpuNums * POOL_SIZE);

  System.out.println("服务器启动");

  }

  public void service()

  {

  while (true)

  {

  Socket socket = null;

  try

  {

  // 客户进行连接就会触发accept方法从而建立连接

  socket = serverSocket.accept();

  // 调用线程池操作

  executorService.execute(new Handler(socket));

  }

  catch (Exception e)

  {

  e.printStackTrace();

  }

  }

  }

  public static void main(String[] args) throws IOException

  {

  new MultiThreadServer1()。service();

  }

  }

  /**

  * 多线程处理类

  */

  class Handler implements Runnable

  {

  private Socket socket;

  public Handler(Socket socket)

  {

  this.socket = socket;

  }

  private BufferedReader getReader(Socket socket) throws IOException

  {

  InputStream socketIn = socket.getInputStream();

  // InputStreamReader为转换流

  // InputStream本是字节流,现加一个Reader,表示用字符流的方式读取字节流

  InputStreamReader isr = new InputStreamReader(socketIn);

  return new BufferedReader(isr);

  }

  public void run()

  {

  try

  {

  BufferedReader br = getReader(socket);

  String msg = null;

  while ((msg = br.readLine()) != null)

  {

  System.out.println("客户端的IP:" + socket.getInetAddress()。getHostAddress());

  System.out.println("客户端的端口:" + socket.getPort());

  System.out.println("客户端的信息:" + msg);

  }

  }

  catch (IOException e)

  {

  e.printStackTrace();

  }

  finally

  {

  try

  {

  if (socket != null)

  {

  socket.close();

  }

  }

  catch (IOException e)

  {

  e.printStackTrace();

  }

  }

  }

  }

  两个多线程服务端执行结果相同

  服务器启动

  客户端的IP:127.0.0.1

  客户端的端口:3931

  客户端的信息:我是小明2

  客户端的IP:127.0.0.1

  客户端的端口:3928

  客户端的信息:我是小明10