指网络上的不同主机,通过不同的进程,以编程的方式进行网络通信(网络数据传输)
发送和接收端是相对的,一台主机可以是接收端也可以是发送端
先有请求,再有响应
由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信基本操作单元
Socket通信模型Socket通信通过IP地址和端口号来联系,IP地址就像楼号,端口号就是门牌号,通过IP和端口的组合就可以找到这个通信的目的端口
对于数据报而言,传输的数据是打包的,如:发送的数据为100byte,必须一次发送,接受的时候也必须接收100byte,并且为一次同时接收
特点:
UDP socket
构造方法:
DatagramSocket() | 创建一个UDp数据包套接字的Socket,绑定本机的任意一个端口(一般用于客户端) |
DatagramSocket(int port) | 创建一个UDp数据包套接字的Socket,绑定本机的一个指定端口port(一般用于服务端) |
方法:
void receive(DatagramPacket p) | 从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待) |
void send(DatagramPacket p) | 从此套接字发送数据报包(不会阻塞等待,直接发送) |
void close() | 关闭此数据报套接字 |
这是UDP发送和接收的数据报
构造方法:
DatagramPacket(byte[] buf, int length) | 构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length) |
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) | 构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号 |
在构造UDP发送的数据报时需要传入的参数SocketAddress对象可以用下面的InetSocketAddrerss来创建,该对象包含了IP和端口号
方法:
InetAddress getAddress() | 从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址 |
int getPort() | 从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号 |
byte[] getData() | 获取数据报中的数据 |
InetSocketAddress ( SocketAddress 的子类 )构造方法:
InetSocketAddress(InetAddress addr, int port) | 创建一个Socket地址,包含IP地址和端口号 |
UDP服务端
public class UDPEchoServer {
private DatagramSocket socket = null;
//构造方法:port为该服务器绑定的端口
public UDPEchoServer(int port) throws SocketException{
socket = new DatagramSocket(port);
}
//启动服务器
public void start() throws IOException{
System.out.println("Server start !");
while(true){
//1.读取请求并解析
DatagramPacket requestPacket = new DatagramPacket(new byte[2048],2048);
socket.receive(requestPacket);
//将接收到的DatagramPacket转换为字符串打印
String request = new String(requestPacket.getData(),0, requestPacket.getLength());
//2.根据请求计算响应
String response = process(request);
//3.把响应写回到客户端
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
response.getBytes().length,requestPacket.getSocketAddress()); //SocketAddress包括IP和Port
socket.send(responsePacket);
//4.格式化打印一个日志,记录当前的情况
System.out.printf("[%s : %d] req:%s ; resp:%s\n",requestPacket.getAddress().toString(),
requestPacket.getPort(),request,response);
}
}
public String process(String request){
return request; //因为是回显服务器,所以没有其他处理,直接返回
}
public static void main(String[] args) throws IOException {
UDPEchoServer server = new UDPEchoServer(6666); //指定端口号6666
server.start();
}
}
运行代码:显示服务端开始运行
UDP客户端
//客户端
public class UDPEchoClient {
private DatagramSocket socket = null; //新建socket对象
private String severIP; //服务器IP
private int severPort; //服务器端口
//构造方法
public UDPEchoClient(String severIP,int serverPort)throws SocketException {
//客服端没有指定端口,让系统自动分配一个空闲的端口
socket = new DatagramSocket();
this.severIP = severIP;
this.severPort = serverPort;
}
public void start() throws IOException{
Scanner scanner = new Scanner(System.in);
while(true){
//1.获得输入的内容
System.out.println("->");
String request = scanner.next();
//2.构造一个UDP请求,发送给服务器
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
request.getBytes().length, InetAddress.getByName(this.severIP),
this.severPort);
socket.send(requestPacket);
//3.从服务器读取UDP响应数据并解析
DatagramPacket responsePacket = new DatagramPacket(new byte[2048],2048);
socket.receive(responsePacket);
String response = new String(responsePacket.getData(),0,responsePacket.getLength());
//4.把服务器的响应显示到控制台上
System.out.println(response);
}
}
public static void main(String[] args) throws IOException {
UDPEchoClient udpEchoClient = new UDPEchoClient("127.0.0.1",6666); //IP地址和指定端口号
udpEchoClient.start();
}
}
运行代码:显示输入
输入一行字后
TCP回显服务器
Server服务端
public class TCPEchoServer {
private ServerSocket listenSocket = null; //创建ServerSocket对象
public TCPEchoServer(int port) throws IOException {
listenSocket = new ServerSocket(port);
}
public void start() throws IOException {
System.out.println("Server started!");
ExecutorService pool = Executors.newCachedThreadPool(); //创建一个线程池
while(true){
//1.先调用accept来接收客户端的连接
Socket clientSocket = listenSocket.accept();
//2.处理这个连接(在线程池中)
pool.submit(new Runnable() {
@Override
public void run() {
try {
processConnection(clientSocket);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
}
}
public void processConnection(Socket clientSocket) throws IOException {
//格式化输出日志
System.out.printf("[%s:%d] Server online!\n",clientSocket.getInetAddress().toString(),
clientSocket.getPort());
//处理客户端的请求
try(InputStream inputStream = clientSocket.getInputStream();
OutputStream outputStream = clientSocket.getOutputStream()) { //创建输入输出流的实例
while(true){
//1.读取请求并解析
Scanner scanner = new Scanner(inputStream); //注意这里的输入参数是输入流
if(!scanner.hasNext()){
//读取完毕,断开连接
System.out.printf("[%s:%d] Server offline!\n",clientSocket.getInetAddress().toString(),
clientSocket.getPort());
break;
}
//2.输入请求
String request = scanner.next();
//3.根据请求计算响应
String response = process(request);
//4.把响应写回客户端
PrintWriter printWriter = new PrintWriter(outputStream); //参数为输出流
printWriter.println(response);
printWriter.flush(); //刷新缓冲区,确保数据已经通过网卡发送出去
//格式化打印日志
System.out.printf("[%s:%d] req: %s;resp: %s\n",clientSocket.getInetAddress().toString(),
clientSocket.getPort(),request,response);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
//关闭Socket
clientSocket.close();
}
}
public String process(String request){
return request; //回显
}
public static void main(String[] args) throws IOException {
TCPEchoServer tcpEchoServer = new TCPEchoServer(6666);
tcpEchoServer.start();
}
}
Client客户端
public class TCPEchoClient {
private Socket socket = null;
public TCPEchoClient(String serverIP,int serverPort) throws IOException {
socket = new Socket(serverIP,serverPort);
}
public void start(){
Scanner scanner = new Scanner(System.in);
try(InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream()) {
while(true){
//1.控制台输入请求
System.out.println("->"); //提示输入
String request = scanner.next();
//2.向服务器发送请求
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.println(request);
printWriter.flush(); //刷新缓冲区,确保数据已经通过网卡发送出去
//3.从服务器读取响应
Scanner responseScanner = new Scanner(inputStream); //参数为输入流
String response = responseScanner.next();
//4.输出打印响应
System.out.println(response);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws IOException {
TCPEchoClient tcpEchoClient = new TCPEchoClient("127.0.0.1",6666);
tcpEchoClient.start();
}
}