-
Java客户套接字类 Socket
-
服务器套接字类 ServerSocket
-
字符串读/写类 BuffferedReader/PrintWriter。
-
服务进程首先被动打开一个监听端口,如8008,客户进程主动访问这个端口,完成对话聊天前的TCP三次握手连接。TCP连接成功后,通信进程的双方具有两个流(输出流和输入流)。逻辑上可将两个流理解为两个通信管道的全双工通信模式,一个用于向对方发送数据,另一个用于接收对方的数据。
image.png -
套接字类有两个基本的方法可以获得两个通信管道的入口:
- Socket.getInputStream()方法可获得输入字节流的入口地址;
- Socket.getOutputStream()方法可获得输出字节流的出口地址;
-
socket.close() 实现四次握手断开
image.png
TCP客户端
import java.net.*;
import java.io.*;
public class TCPClient {
//嵌套字程序设计
private Socket socket = null;
//用于字符和字节转换的变量
private PrintWriter pw;
private BufferedReader br;
public TCPClient(String ip, String port) throws IOException{
//主动向服务器发起连接,实现TCP中三次握手的过程
socket = new Socket(ip, Integer.parseInt(port));
//若不成功(网络问题,地址错误,服务器资源紧张等),抛出错误,其错误信息交由调用者处理
//若成功,做下面两件事
//得到网络输出字节流地址,并装饰成网络输出字符流
OutputStream socketOut = socket.getOutputStream();
pw = new PrintWriter(new OutputStreamWriter(socketOut,"GB2312"),true);
// pw.flush();
//得到网络输入流地址,并装饰成网络输入字符流
InputStream socketIn = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(socketIn,"GB2312"));
}
public void send(String msg){
pw.println(msg+"\n");
pw.flush();
//输出字符流,由Socket调用系统底层函数,经网卡发送字节流
}
public String receive(){
String msg;
try{
//从网络输入字符流中读信息,每次只能接收一行信息
//若不够一行(无行结束符),该语句阻塞,直到条件满足,程序才往下运行
msg = br.readLine();
}catch(IOException ex){
msg = null;
}
return msg;
}
public void close(){
try{
if(socket != null){
//实现三次握手
socket.close();
}
}catch(IOException ex){}
}
//模块内测试与运行,需要先运行TCPServer
//
// public static void main(String args[])throws IOException{
// TCPClient tc = new TCPClient("127.0.0.1","8008");
// ec.send("123456789"); //发送一行字符
// System.out.println(ec.receive());//接受一行字符串并在屏幕上显示
// tc.close();
//
// }
}
TCP服务器
import java.io.*;
import java.net.*;
public class TCPServer {
private int port = 8008;
//服务器嵌套字
private ServerSocket serverSocket;
public TCPServer()throws IOException{
//开启8008监听端口
serverSocket = new ServerSocket(8008);
System.out.println("服务器启动");
}
private PrintWriter putWriter(Socket socket)throws IOException{
OutputStream socketOut = socket.getOutputStream();//获得输出流缓冲区的地址
return new PrintWriter(new OutputStreamWriter(socketOut,"GB2312"),true);
}
private BufferedReader getReader(Socket socket)throws IOException{
InputStream socketIn = socket.getInputStream();//获得输入流缓冲区的地址
return new BufferedReader(new InputStreamReader(socketIn,"GB2312"));
}
public void service(){
//单客户版本,每次只能同时和一个客户建立通信连接
while(true){
Socket socket = null;
try{
//阻塞语句,监听并等待客户发起连接,有连接请求就生成一个嵌套字
socket = serverSocket.accept();
//本地服务器观测台显示请求的用户信息
System.out.println("新用户:" + socket.getInetAddress());
BufferedReader br = getReader(socket);//定义字符串输入流
PrintWriter pw = putWriter(socket); //定义字符串输出流
String msg;
//阻塞语句,从输入流读入一行字符串
while((msg = br.readLine())!=null){
pw.println("来自服务器:" + msg); //先输出流输出一行字符串
// pw.flush();
if(msg.equals("bye")) //如果客户发送的消息为"bye",就结束通信
break;
}
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(socket!=null)
socket.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
public static void main(String args[])throws IOException{
new TCPServer().service();
}
}
网友评论