和udp相对应的传输层协议就是tcp,他们起到的最基本的功能就i是将IP提供的主机-主机传递服务扩展到端口-端口进程级,就是把数据段从一个电脑上面的应用传递到另一个电脑的应用上。
用tcp实现回显器
服务器
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class TcpEchoServer {
private ServerSocket listenSocket=null;
//关联一个端口号
public TcpEchoServer(int port) throws IOException {
listenSocket=new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("服务器启动");
while (true){
//udp的服务器进入主循环,就直接尝试reeive读取请求了,但是tcp是有连接的
//需要做的是先做好链接当服务器运转的时候是否有客户端来建立连接是不确定的,如果客户端没有链接
//服务器就会阻塞等待,如果建立链接;accept就会返回一个socket对象
//进一步的客户端和服务器之间的交互就交给clientSocket来完成了
Socket clientSocket= listenSocket.accept();
processConnection(clientSocket);
}
}
private void processConnection(Socket clientSocket) throws IOException {
//处理一个链接,在这个链接中可能涉及客户端和服务器的多次交互
String log=String.format("[%s,%d]客户端上线",clientSocket.getInetAddress().toString(),
clientSocket.getPort());
System.out.println(log);
try(InputStream inputStream= clientSocket.getInputStream();
OutputStream outputStream=clientSocket.getOutputStream()) {
while (true){
//1.读取请求并解析
Scanner scanner=new Scanner(inputStream);
if(!scanner.hasNext()){
log=String.format("[%s,%d]客户端下线",
clientSocket.getInetAddress().toString(), clientSocket.getPort());
break;
}
String request=scanner.next();
//2.根据请求计算响应
String response=process(request);
//3.把响应写回客户端
PrintWriter writer=new PrintWriter(outputStream);
writer.println(response);
writer.flush();
log=String.format("[%s,%d]req:%s,resp:%s",clientSocket.getInetAddress().toString(),
clientSocket.getPort(),request,response);
System.out.println(log);
}
}catch (IOException e){
e.printStackTrace();
}finally {
clientSocket.close();
}
}
private String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
TcpEchoServer server=new TcpEchoServer(9090);
server.start();
}
}
客户端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class TcpEchoClient {
private Socket socket=null;
private int serverPort;
private String serverIp;
public TcpEchoClient(String serverIp, int serverPort) throws IOException {
this.serverIp=serverIp;
this.serverPort=serverPort;
//让socket创建的同时和服务器建立连接
this.socket=new Socket(serverIp,serverPort);
}
public void start(){
try (InputStream inputStream= socket.getInputStream();
OutputStream outputStream= socket.getOutputStream()){
while (true){
//1.从键盘上读取用户输入的内容
Scanner scanner=new Scanner(System.in);
System.out.println("->");
String request=scanner.next();
if(request.equals("exit")){
break;
}
//2.把这个读取的内容构造成请求发给服务器
PrintWriter printWriter=new PrintWriter(outputStream);
printWriter.print(request);
//3.从服务器读取响应并解析
Scanner respScanner=new Scanner(inputStream);
String response=respScanner.next();
//4.把结果显示出来
String log=String.format("req,%s;resp;%s",request,response);
System.out.println(log);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
TcpEchoClient tcpEchoClient=new TcpEchoClient("127.0.0.1",9090);
tcpEchoClient.start();
}
}
一般情况下都是先启动服务器再启动客户端,保证服务器时刻等待客户端的命令到来,及时做出反应和信息的处理