TCP协议
IP协议(Internet Protocol)
-
负责计算机之间的通信。将消息从一个主机传送到另一个主机
-
负责在因特网上发送和接收数据包。
TCP协议(Transport Control Protocol)
-
用于从应用程序到网络的数据传输控制。
-
负责在数据传送之前将它们分割为 IP 包,然后在它们到达的时候将它们还原。
-
被称作一种端对端协议,当一台计算机需要与另一台远程计算机连接时,TCP协议会让他们建立一个连接:用于发送和接收数据的虚拟链路。
-
TCP协议使用重发机制:当一个通信实体(A)发送消息给另个通信实体(B)后,需要接收到B的确认信息,如果没有收到确认信息,会再次重发刚发送的信息。
-
URL、URLConnection、Socket、ServerSocket等类都使用TCP协议进行网络通讯
Socket通信
通信原理
- 网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket
- socket通常用来实现客户端(Client)和服务器端(Server)的连接
如下图:
详细:
解读:
-
Server端有一个
ServerSocket
对象用来监听来自客户端的Socket
连接,如果没有连接,它一直处于等待(wait)状态。 -
客户端发起一个请求(request)给服务端,服务端收到request之后,会通过
accept()
方法返回一个Socket
,然后客户端和服务端就会建立起连接(connect)//服务器端创建一个ServerSocket来监听客户端的Socket连接请求 ServerSocket ss = new ServerSocket(2000); //不断接受客户端的请求 while(true){ //每接受到一个客户端Socket,服务器也会对应产生一个Socket Socket s = ss.accept(); //通过socket进行通讯 ... }
-
通过Socket对象获得对方的I/O流,进行数据的读写
-
完成通信后,关闭Socket
代码实现
Socket类:
- Socket()
- Socket(InetAddress address, int port) — 创建远程连接到指定远程主机、远程端口的Socket
- InputStream getInputStream() — 返回该Socket对象对应的输入流,程序通过该输入流从Socket中取出数据(接收来自另一方发送的信息)
- OutputStream getOutputStream() — 返回该Socket对象对应的输出流,程序通过该输出流向Socket中输出数据(往外发东西)
ServerSocket类:
- ServerSocket() — 用指定的端口号(0~65535)创建一个ServerSocket
- Socket accept() — 如果接收到一个客户端Socket的连接请求,返回一个与客户端Socket对应的Socket,否则该方法一直处于等待状态,线程也被阻塞。
客户端Socket的建立
/*
* 第一个参数 host 是目标服务器的地址,"127.0.0.1"通常指的是本机地址,
* 我们自己在写程序的时候,只有一台电脑,我们的电脑同时启动两个虚拟机,一个为服务端,
* 一个是客户端,这个时候服务端的地址就是本机地址
*
* 第二个参数为端口号,只要在范围内并且不取1024下的保留号就可以
* 但是客户端的端口号必须和对应服务端的端口号一致
*/
try {
Socket socket = new Socket("127.0.0.1", 2000);
} catch (IOException e) {
System.out.println("Error:"+e);
}
服务器端Socket的建立
try {
ServerSocket serverSocket = new ServerSocket(2000);
Socket socket = serverSocket.accept();
} catch (IOException e) {
System.out.println("Error:"+e);
}
构建输入输出流
方法一:
//获得输出流---往外发信息
PrintStream os = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
//获得输入流---接收来自另一方发送的信息
DataInputStream is = new DataInputStream(socket.getInputStream());
方法二:
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
/*
* InputStreamReader 转换流(字节到字符的转换)
* PrintWriter 打印输出流
* BufferedReader 缓冲流
* DataInputStream 数据操作流
*/
例:
简单的命令行聊天系统
服务器端
package com.sehun.socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
//服务端
public class ServerDemo {
public static void main(String[] args) {
try {
ServerSocket serverSocket = null;
Socket socket = null;
try {
serverSocket = new ServerSocket(3999);
System.out.println("Server Run !");
socket = serverSocket.accept();
System.out.println("客户端已连接\n");
}catch (IOException e){
System.out.println("连接失败");
}
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
//输出流,将服务端的内容发送给客户端
PrintWriter out = new PrintWriter(socket.getOutputStream());
//输入流,读取来自客户端发给它的信息
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String readLine = in.readLine();
System.out.println("Client: "+readLine);
String line = sin.readLine();
while (!line.equals("over")){
out.println(line);
out.flush();
readLine = in.readLine();
if (readLine==null){
System.out.println("客户端已下线,请输入【over】结束本次聊天");
}else
System.out.println("Client: " + readLine);
line = sin.readLine();
}
out.close();
in.close();
socket.close();
serverSocket.close();
} catch (Exception e) {
System.out.println("Error:"+e);
}
}
}
客户端:
package com.sehun.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
//客户端
public class ClientDemo {
public static void main(String[] args) {
try {
Socket socket = null;
try {
socket = new Socket("127.0.0.1", 3999);
System.out.println("Client Run!\n");
}catch (IOException e){
System.out.println("连接服务端失败");
}
//键盘输入流,获取用户从键盘输入的信息
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
//输出流,从客户端将信息发送给服务端
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
//输入流,接收来自网络上服务端发送给本程序的信息
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = sin.readLine();
String readLine = null;
//用户通过“over”字符串来告诉程序是否结束
while(!line.equals("over")){
out.println(line);
//强制输出数据(清空缓冲区的数据流)
out.flush();
readLine = in.readLine();
if (readLine==null){
System.out.println("服务端已下线,请输入【over】结束本次聊天");
}else
System.out.println("Server: "+readLine);
line = sin.readLine();
}
out.close();
in.close();
socket.close();
} catch (Exception e) {
System.out.println("Error:"+e);
}
}
}
运行结果: