本文探讨一下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连接。