socket通过三次握手建立连接,通信完成时拆除连接
四要素是:客户端地址,客户端端口,服务端地址,服务端端口
客户端和服务端的代码编写
关于 Thread 类(https://blog.csdn.net/qq_58266033/article/details/123638588)
在java标准库中,提供了一个Thread类,用来表示/操作线程,Thread类可以视为是Java标准库提供的API,Java是支持多线程编程的,在Java中创建好的Thread实例,其实和操作系统中的线程是一一对应的关系,操作系统提供了一组关于线程的API(C语言),Java对于这组API进一步封装之后就变成了Thread类
最简单的创建线程方式 写一个类继承线程Thread类 再重写run方法
服务端Server.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
// 新建一个服务器socket 只需要设置端口即可 不需要设置ip
ServerSocket server = new ServerSocket(2000);
System.out.println("服务器准备就绪--");
System.out.println("服务器信息:"+server.getInetAddress()+" P:"+server.getLocalPort());
// 无限循环 接收来自客户端的请求
for (;;){
// 接受客户端 获得客户端的client信息
Socket client = server.accept();
// 握手接收到以后 开一个线程执行线程里面的操作
ClientHandler clientHandler = new ClientHandler(client);
// 线程执行
clientHandler.start();
}
}
// 新建一个类 继承线程里面的方法
private static class ClientHandler extends Thread{
private Socket socket;
private boolean flag = true;
ClientHandler(Socket socket){
this.socket = socket;
}
//重写线程里面的run方法
@Override
public void run() {
// 先继承原有run方法
super.run();
// 打印出客户端的相关信息
System.out.println("新客户端连接:"+socket.getInetAddress()+" P:"+socket.getPort());
try {
//得到打印流 用于数据输出;服务器
//客户端的输出流 作为一个打印流
PrintStream socketOutput = new PrintStream(socket.getOutputStream());
//客户端的输入流 转换为BufferedReader
BufferedReader socketInput = new BufferedReader(new InputStreamReader(socket.getInputStream()));
do{
//客户端拿到一条数据
//从打印流拿到数据
String str = socketInput.readLine();
if("bye".equalsIgnoreCase(str)){
flag=false;
socketOutput.println("bye");
}else {
System.out.println(str);
//输出流往客户端写东西
socketOutput.println("回送"+str.length());
}
}
while (flag);
}catch (Exception e){
System.out.println("连接异常断开");
}finally {
try {
socket.close();
}catch (IOException e){
e.printStackTrace();
}
}
System.out.println("客户端已退出:"+socket.getInetAddress()+" P:"+socket.getPort());
}
}
}
客户端Client.java
import java.io.*;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.Socket;
// 新建一个客户端
public class Client {
// main函数
public static void main(String[] args) throws IOException {
// 新建一个socket
Socket socket = new Socket();
// 设置超时时间
socket.setSoTimeout(3000);
// 设置连接本地 端口2000;超时时间3000
socket.connect(new InetSocketAddress(Inet4Address.getLocalHost(),2000),3000);
System.out.println("已发起服务器连接,并进入后续流程--");
System.out.println("客户端信息:"+socket.getLocalAddress()+" P:"+socket.getLocalPort());
System.out.println("服务器信息:"+socket.getInetAddress()+" P:"+socket.getPort());
//连接到服务器以后 做todo()方法的相关操作 传入socket参数是为了得到服务器的输入流和输出流
try {
todo(socket);
}catch (Exception e){
System.out.println("异常关闭");
}
// 释放资源
socket.close();
System.out.println("客户端已退出");
}
public static void todo(Socket client) throws IOException {
// BufferedReader 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
// 构建键盘输入流
//将InputStreamReader转为BufferedReader
InputStream inputStream= System.in;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
// 得到Client输出流,并转换为打印流
// outputStream 直接转换为PrintStream 打印流
OutputStream outputStream = client.getOutputStream();
PrintStream socketPrintStream = new PrintStream(outputStream);
// 得到Client输入流,并转换为BufferedRead
InputStream inputStream1 = client.getInputStream();
BufferedReader bufferedReader1 = new BufferedReader(new InputStreamReader(inputStream1));
boolean flag = true;
do {
//键盘读取一行
String str = bufferedReader.readLine();
// 通过打印流发送到服务器
socketPrintStream.println(str);
//从服务器读取一行
String echo = bufferedReader1.readLine();
// 如果是bye则不做操作 否则打印出来
if ("bye".equalsIgnoreCase(echo)) {
}else{
System.out.println(echo);
}
}
// 重复输入 直到断开
while(flag);
//关闭socketPrintStream 释放内存
socketPrintStream.close();
}
}