Bootstrap

java实现基础的一对一和一对多的TCP通信

本文探讨一下java的TCP通信,首先先实现一对一的tcp连接:

先来看一下tcp的特点:

面向连接的TCP 

     TCP面向连接通信,所以握手过程会消耗资源,过程为可靠连接,不会丢失数据,适合大数据量交换 

     “面向连接”就是在正式通信前必须要与对方建立起连接。
     TCP协议能为应用程序提供可靠的通信连接,使一台计算机发出的字节流无差错地发往网络上的其他计算机,对可靠性要求高的数据通信系统往往使用TCP协议传输数据。

下面实现一对一的tcp,首先写一个Server类做服务器,放在com.tcp包下,注释写得很清楚了,请注意看注释:


package com.tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/*
 * ServerSocket测试 作为tcp网络通信的服务器端
 * 1、创建ServerSocket对象,绑定监听端口
 * 2、通过accept()方法监听客户端请求
 * 3、连接建立后,通过输入流读取客户端发送的请求信息 
 * 4、通过输出流向客户端发送响应信息
 * 5、关闭相关资源
 * */
public class Server {
    public static void main(String[] args) {
        try {
            //1、创建一个服务器端Socket,即ServerSocket,绑定指定的端口,进行监听
            ServerSocket serverSocket = new ServerSocket(8888);
            System.out.println("服务器即将启动,等待客户端连接");
            //2、调用accept()方法 开始监听 等待客户端连接
            Socket socket = serverSocket.accept();//ctrl+shift+o快速导入需要的包
            //3、获取输入流 并读取客户端信息
            InputStream is = socket.getInputStream();//字节输入流
            InputStreamReader isr = new InputStreamReader(is);//将字节流转化为字符流
            BufferedReader br = new BufferedReader(isr);//为输入流添加缓冲
            String info=null;
            while((info = br.readLine())!=null){//循环读取客户端信息
                System.out.println("我是服务器,客户端说"+info);
            }
            socket.shutdownInput();
            //4、获取输出流 响应客户端的请求
            OutputStream os= socket.getOutputStream();
            PrintWriter pw = new PrintWriter(os);//包装为打印流
            pw.write("欢迎您");
            pw.flush();//缓冲输出
            //5、关闭资源
            //服务器调用了socket.close()和serverSocket.close()以后就不需要调用其它close()方法了 因为相当于中断了连接 相应的流通道也断开了
            //同理客户端也是调用socket.close()就可以了
            socket.close();
            serverSocket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
}

接下来写一个Client类做客户端,同样放在com.tcp下:


package com.tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

/*
 * Socket测试  作为tcp的客户端:
 * 1、创建Socket对象,指明需要连接的服务器的地址和端口号
 * 2、连接建立以后,向服务器端发送请求信息
 * 3、通过输入流获取服务器响应的信息
 * 4、关闭相关资源
 * */
public class Client {
    public static void main(String[] args) {
        try {
            //1、创建客户端Socket,指定服务器地址和端口
            Socket socket = new Socket("localhost",8888);
            //2、获取输出流,向服务器发送信息
            OutputStream os = socket.getOutputStream();//字节输出流
            PrintWriter pw = new PrintWriter(os);//将输出流包装为打印流
            pw.write("我是客户端 我在说话");
            pw.flush();
            socket.shutdownOutput();//关闭输出流
            //3、获取输入流,并且读取服务器端的响应信息
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String info=null;
            while((info = br.readLine())!=null){//循环读取服务器信息
                System.out.println("我是客户端,服务器说"+info);
            }
            //4、关闭资源
//            socket.close();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
}

这样便实现了TCP的一对一通信。

下面我们来实现TCP的一对多连接,客户端的代码不需要改变,我们只需要改变服务器端的代码,让其循环监听客户端,然后新建一个线程类即可。

首先新建一个线程类ServerThread 放在com.tcp下:

package com.tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

/*
 * 服务器线程处理类
 * */
public class ServerThread extends Thread {
    //和本线程相关的Socket
    Socket socket = null;
    
    public ServerThread(Socket socket){
        this.socket = socket;
    }
    
    //线程执行的操作 响应客户端的请求
    public void run(){
        try {
            //3、获取输入流 并读取客户端信息
            InputStream is = socket.getInputStream();
            //字节输入流
            InputStreamReader isr = new InputStreamReader(is);//将字节流转化为字符流
            BufferedReader br = new BufferedReader(isr);//为输入流添加缓冲
            String info=null;
            while((info = br.readLine())!=null){//循环读取客户端信息
                System.out.println("我是服务器,客户端说"+info);
            }
            socket.shutdownInput();
            //4、获取输出流 响应客户端的请求
            OutputStream os= socket.getOutputStream();
            PrintWriter pw = new PrintWriter(os);//包装为打印流
            pw.write("欢迎您");
            pw.flush();//缓冲输出
            //5、关闭资源
            //服务器调用了socket.close()和serverSocket.close()以后就不需要调用其它close()方法了 因为相当于中断了连接 相应的流通道也断开了
            //同理客户端也是调用socket.close()就可以了
        } 
        catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally{//无论如何都关闭socket
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

然后将服务器端的代码在线程类的基础上进行一下变化:

package com.tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/*
 * ServerSocket测试 作为tcp网络通信的服务器端
 * 1、创建ServerSocket对象,绑定监听端口
 * 2、通过accept()方法监听客户端请求
 * 3、连接建立后,通过输入流读取客户端发送的请求信息 
 * 4、通过输出流向客户端发送响应信息
 * 5、关闭相关资源
 * */
public class Server {
    public static void main(String[] args) {
        try {
            //记录链接过的客户端个数
            int count=0;
            //1、创建一个服务器端Socket,即ServerSocket,绑定指定的端口,进行监听
            ServerSocket serverSocket = new ServerSocket(8888);
            System.out.println("服务器即将启动,等待客户端连接");
            //2、循环监听等待客户端的连接
            while(true){
                //调用accept方法 等待客户端的连接
                Socket socket = serverSocket.accept();
                //创建一个新的线程
                ServerThread serverThread = new ServerThread(socket);
                //启动线程
                serverThread.start();
                count++;
                System.out.println("连接过的客户端数量为:"+count);
            }
//            serverSocket.close();//这是一个死循环 所以执行不到这里 服务器会一直运行
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
}

到这里,我们就完成了一个很基础的一对一tcp和一对多tcp连接。

;