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