需求和分析
用java实现文本转换器
这是一个TCP连接。客户端将文本发送到服务端,服务端会将文本转换成大写形式,并返回给客户端。当客户端发送“over”的时候,就关闭客户端和服务端。
分析:
1、客户端
客户端从键盘录入数据,然后发送到服务端。这个过程中,源是键盘录入,目的是网络输出流,并且都是字符,因此可以使用字符流。为了提高效率,加入缓冲区技术。如果键盘录入的是“over”,那么会发送“over”,并且关闭资源。
客户端从网络输入流中接收服务端发来的大写形式,这个过程中,源是网络输入流,目的是控制台,直接输出即可。
2、服务端
服务端从网络输入流中获取数据,这个过程中,源是网络输入流,使用加入缓冲区技术的字符流。对接收的文本进行处理,如果是“over”,那么直接关闭资源,如果不是,那么对其进行大写转换,然后发送给客户端,这个过程中,目的是网络输出流。
3、注意
在输出流中,如果使用BufferedWriter对象,那么注意写入数据之后一定要flush,否则数据只是写到了缓冲区,并没有写到真正的目的。因为对方读取都是调用readLine(),这是阻塞式方法,必须有换行符才可以,否则一直阻塞,因此写的时候,需要加入换行符。
当然也可以使用PrintWriter,调用println()能够将数据直接输出到指定流中,并且自动换行。PrintWriter(OutputStream/Writer out, true)中的true可以使得流能够有效的自动刷新,该类的构造函数,既可以接收字节流,也可以接收字符流,因此更为简便。
当客户端关闭连接的时候,会向socket流中写入-1,这样服务端在读到-1的时候,就知道客户端关闭了连接,就会关闭服务器的socket服务,通信结束。代码1-3都是使用了客户端和服务端两个线程,代码4将客户端拆成发送线程和接收线程,更符合实际通信过程。
代码1:
/*
使用字节流进行读写操作。
*/
import java.io.*;
import java.net.*;
//客户端
class TCPClient{
public static void main(String[] args)throws Exception{
//创建socket服务,并建立到服务器的连接
Socket s = new Socket("192.168.254.136", 8000);
//键盘录入需要转换的文本
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//网络输出流,将键盘录入的数据输出到输出流中,发送到服务端
OutputStream out = s.getOutputStream();
InputStream in = s.getInputStream();
String line = null;
while((line = bufr.readLine()) != null){
out.write(line.getBytes());
if("over".equals(line)){
break;
}
//循环接收数据
byte[] buf = new byte[1024];
int len = in.read(buf);
String data = new String(buf, 0, len);
System.out.println("文本转换后:"+data);
}
//关闭资源
bufr.close();
s.close();
}
}
//服务端
class TCPServer{
public static void main(String[] args)throws Exception{
//创建socket服务,监听指定端口
ServerSocket ss = new ServerSocket(8000);
//阻塞等待客户端的连接请求
Socket cs = ss.accept();
//通过客户端的socket获取输入流
InputStream in = cs.getInputStream();
//通过客户端的sokcet获取输出流
OutputStream out = cs.getOutputStream();
//循环接收和发送数据
while(true){
byte[] buf = new byte[1024];
int len = in.read(buf);
if(len > 0){
String data = new String(buf, 0, len);
//如果是over,就关闭资源
if("over".equals(data)){
break;
}
System.out.println("客户端发来的文本是:"+data);
out.write(data.toUpperCase().getBytes());
}
else{
break;
}
}
//关闭资源
cs.close();
ss.close();
}
}
代码2:
/*
使用加入了缓冲技术的字符流,注意flush和添加换行符
*/
import java.io.*;
import java.net.*;
//客户端
class TCPClient{
public static void main(String[] args)throws Exception{
//创建socket服务,并建立到服务器的连接
Socket s = new Socket("192.168.254.136", 8000);
//键盘录入需要转换的文本
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//通过socket流获取输出流,将文本数据发送到服务端
BufferedWriter bufout = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//通过socket流获取输入流,获取服务端发来的数据
BufferedReader bufin = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line = bufr.readLine()) != null){
//将文本数据发送到服务端
bufout.write(line);
bufout.newLine();//换行符表示一个完整的独立文本数据
bufout.flush();
//如果发送的的over,那么退出并关闭资源
if("over".equals(line)){
break;
}
//通过网络输入流获取转换结果
String data = bufin.readLine();
System.out.println("转换后的结果是:"+data);
}
//关闭资源
s.close();
bufr.close();
bufin.close();
bufout.close();
}
}
//服务端
class TCPServer{
public static void main(String[] args)throws Exception{
//创建socket服务,监听指定端口
ServerSocket ss = new ServerSocket(8000);
//阻塞等待客户端的连接请求
Socket cs = ss.accept();
//通过客户端的socket获取网络输入流
BufferedReader bufin = new BufferedReader(new InputStreamReader(cs.getInputStream()));
//通过客户端的socket获取网络输出流
BufferedWriter bufout = new BufferedWriter(new OutputStreamWriter(cs.getOutputStream()));
String line = null;
while((line = bufin.readLine()) != null){
//当发送的是over,那么退出并关闭资源
if("over".equals(line)){
break;
}
System.out.println("客户端发来的文本数据是:"+line);
//将转换后的数据发送给客户端
bufout.write(line.toUpperCase());
bufout.newLine();//换行符使数据成为独立完整的文本
bufout.flush();//将数据写入目的中
}
//关闭资源
cs.close();
ss.close();
bufin.close();
bufout.close();
}
}
代码3:
/*
使用打印字符流,可以避免flush和添加换行符的操作,实现更简便。
*/
import java.io.*;
import java.net.*;
//客户端
class TCPClient{
public static void main(String[] args)throws Exception{
//创建socket服务,并建立到服务器的连接
Socket s = new Socket("192.168.254.136", 8000);
//键盘录入需要转换的文本
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//通过socket流获取输出流,将文本数据发送到服务端
PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
//通过socket流获取输入流,获取服务端发来的数据
BufferedReader bufin = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line = bufr.readLine()) != null){
//将文本数据发送到服务端
pw.println(line);//连同数据和换行符一并写到目的中
//如果发送的的over,那么退出并关闭资源
if("over".equals(line)){
break;
}
//通过网络输入流获取转换结果
String data = bufin.readLine();
System.out.println("转换后的结果是:"+data);
}
//关闭资源
s.close();
bufr.close();
bufin.close();
pw.close();
}
}
//服务端
class TCPServer{
public static void main(String[] args)throws Exception{
//创建socket服务,监听指定端口
ServerSocket ss = new ServerSocket(8000);
//阻塞等待客户端的连接请求
Socket cs = ss.accept();
//通过客户端的socket获取网络输入流
BufferedReader bufin = new BufferedReader(new InputStreamReader(cs.getInputStream()));
//通过客户端的socket获取网络输出流
PrintWriter pw = new PrintWriter(cs.getOutputStream(), true);
String line = null;
while((line = bufin.readLine()) != null){
//当发送的是over,那么退出并关闭资源
if("over".equals(line)){
break;
}
System.out.println("客户端发来的文本数据是:"+line);
//将转换后的数据发送给客户端
pw.println(line.toUpperCase());
}
//关闭资源
cs.close();
ss.close();
bufin.close();
pw.close();
}
}
代码4:
/*
客户端
1、发送线程
键盘录入发送数据,直到输入over的时候,就不能发送,退出线程并关闭资源
2、接收线程
一直开启,但是当发送端发送over的时候,会关闭客户端套接字,使得接收线程也无法运行
服务端
服务端也是有发送端和接收端,接收端接收到数据然后处理,通过发送端发送出去,所以发送端和接收端共用这个数据资源,为了简化操作,将发送和接收放在一个线程中
*/
import java.io.*;
import java.net.*;
//客户端的发送线程
class TCPClientSend implements Runnable{
private Socket s;
//构造函数
TCPClientSend(Socket s){
this.s = s;
}
//复写run(),线程启动即执行此函数
public void run(){
try{
//键盘录入
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//获取socket流中的输出流,并转成字符流,加入缓冲技术
BufferedWriter bufout = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while((line = bufr.readLine()) != null){
//将键盘录入的数据发送到服务端
bufout.write(line);
bufout.newLine();
bufout.flush();
//如果发送的是over,那么退出线程并关闭资源
if("over".equals(line)){
break;
}
}
//关闭资源
bufr.close();
bufout.close();
s.close();
}
catch(Exception e){
throw new RuntimeException("send exception");
}
}
}
//客户端的接收线程
class TCPClientRecv implements Runnable{
private Socket s;
//构造函数
TCPClientRecv(Socket s){
this.s = s;
}
//复写run(),线程开启就执行该函数
public void run(){
try{
//一直在接收,所以用循环
while(true){
//获取socket流的输入流,获取数据
BufferedReader bufin = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line = bufin.readLine()) != null){
System.out.println("转换后的内容是:"+line);
}
}
}
catch(Exception e){
throw new RuntimeException("receive exception");
}
}
}
//客户端
class Tcp_Client{
public static void main(String[] args)throws Exception{
//创建socket服务,并和服务端建立连接
Socket s = new Socket(InetAddress.getLocalHost(), 8000);
//开启发送和接收线程
new Thread(new TCPClientSend(s)).start();
new Thread(new TCPClientRecv(s)).start();
}
}
//服务端
class Tcp_Server{
public static void main(String[] args)throws Exception{
//创建socket服务,监听指定端口
ServerSocket ss = new ServerSocket(8000);
//阻塞等待客户端的连接请求
Socket cs = ss.accept();
//通过客户端的套接字获取网络输入流,获取客户端发来的信息
BufferedReader bufin = new BufferedReader(new InputStreamReader(cs.getInputStream()));
//通过客户端的套接字获取网络输出流,将转换后的大写形式发送给客户端
PrintWriter out = new PrintWriter(cs.getOutputStream(), true);
String line = null;
while((line = bufin.readLine()) != null){
//如果收到了over,那么退出并关闭资源
if("over".equals(line)){
break;
}
System.out.println("客户端发来数据:"+line);
//将转换后的大写形式发送给客户端
out.println(line.toUpperCase());//直接将大写形式写到输出流中并且换行
}
//关闭资源
bufin.close();
out.close();
cs.close();
ss.close();
}
}