一、Socket网络编程
1.1 C/S和B/S架构
-
C/S:client/server,客户端/服务端
-
B/S:browser/server,浏览器/服务端,浏览器本质来说也是一个标准的客户端。
1.2 TCP和UDP(面试题)
-
TCP协议:全称传输控制协议,其实它是一种面向连接的,并且可靠的,底层基于字节流进行传输数据的协议。传输数据的时候因为需要保证将数据信息完全的传输到目标位置,所有在这里它具有传输速度慢,占用资源多的相关缺点,优点就是传输数据的大小不受限制,并且可以将数据完整的进行传输。
eg:文件的传输,TCP协议底层是应用了三次握手(发送、接收、响应)
-
UDP协议:UDP协议主要应用于数据传输的实时性时使用,传输数据的速度较快,占用资源少,数据传输的的大小一般是64之内的数据。例如经常使用的微信通话,腾讯会议的使用上。使用UDP协议也会带来一些弊端,当遇到网络问题时,可能在网络异常时传递的数据就无法被接收到,当恢复网络以后,就会从网络状态ok后的情况进行数据的传输。
-
补充:即时通讯常用的网站:腾云、环信
1.3 Socket概述
Socket中文含义"套接字",主要使用Socket描述IP地址和端口号,是一个通信链的句柄。应用程序通常使用Socket向网络发出请求或者应答。
1.4 聊天室案例一
业务场景:使用Java的Socket实现客户端和服务器端之间的连接,并使客户端向服务端发送一条消息。
客户端 | 服务端 |
---|---|
客户端向服务端发送“您好,服务端!!!” | 服务端接收客户端信息,并显示在控制台中 |
Server端
package cn.tedu.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 聊天室服务器端案例一
* @author cjn
*
*/
public class Server {
/*
* 声明ServerSocket属性
* 服务端使用的socket对象是ServerSocket,
* 需要通过该对象进行申请服务的端口号,如果
* 服务器端需要获取客户端发送的数据消息,
* 需要和客户端书写的端口号一致,只有这样
* 才可以进行监听到客户端所发送的消息
*/
private ServerSocket serverSocket;
/**
* 添加构造器方法,用于对属性的初始化操作
* @param args
*/
public Server() {
try {
//启动类以后,进行对ServerSocket进行初始化
System.out.println("服务器端正在启动...");
//创建ServerSocket实例以后需要指定端口号
serverSocket = new ServerSocket(8888);
System.out.println("服务器端启动成功!!!");
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 用于获取输入流对象,并且接收客户端发送的消息
* @param args
* @throws IOException
*/
public void start() {
try {
System.out.println("等待客户端连接...");
/*
* 连接客户端,ServerSocket提供了一个accept接收客户端连接的方法
* accept方法本身也是一个阻塞方法,没有客户端连接时会一直等待客户端连接
*/
Socket socket = serverSocket.accept();
System.out.println("一个客户端连接完毕!!!");
//通过socket实例获取输入流对象
InputStream is = socket.getInputStream();
//流连接进行优化读取数据
InputStreamReader isr = new InputStreamReader(is);//字符转换流
BufferedReader br = new BufferedReader(isr);//缓冲字符输出流
//按行读取数据
String message = br.readLine();
//打印客户端发送过来的消息数据
System.out.println("服务端接收到客户端发送的消息是:"+message);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Server server = new Server();
server.start();
}
}
Client端
package cn.tedu.socket;
/**
* 聊天室客户端案例一
* @author cjn
*
*/
import java.io.BufferedWriter;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
public class Client {
/*
* 声明Socket属性,用于客户端向服务器端发送数据,
* Socket内部封装了TCP协议,是一个安全可靠协议
*/
private Socket socket;
/**
* 添加客户端无参构造器,用于对属性的初始化操作
* @param args
*/
public Client() {
try {
System.out.println("开始连接服务端...");
/*
* Socket第一个参数代表的是服务器端的IP
* 第二个参数代表的是服务器端的端口号
* 127.0.0.1
*/
socket = new Socket("localhost", 8888);
System.out.println("连接服务端成功!!!");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 客户端向服务器端写出数据的方法
* @param args
*/
public void start() {
try {
//从socket对象中进行获取输出流对象
OutputStream os = socket.getOutputStream();
//使用流连接的方式,使用高级流进行数据的写出
OutputStreamWriter osw = new OutputStreamWriter(os);//字符转换流
BufferedWriter bw = new BufferedWriter(osw);//字符缓冲流
PrintWriter pw = new PrintWriter(bw,true);//自动行刷新
//向服务端发送数据
pw.println("您好,服务器端!!!");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Client client = new Client();
client.start();
}
}
测试结果:
切换服务端与客户端:
(1)客户端控制台:
开始连接服务端...
连接服务端成功!!!
(2)服务器端控制台:
服务器端正在启动...
服务器端启动成功!!!
等待客户端连接...
一个客户端连接完毕!!!
服务端接收到客户端发送的消息是:您好,服务器端!!!
1.5 聊天室案例二
业务功能:希望基于聊天室案例一的功能基础之上,可以让客户端不断的向服务器端发送消息。
Client客户端的start方法进行修改:
/**
* 客户端向服务器端写出数据的方法
* @param args
*/
public void start() {
try {
//从socket对象中进行获取输出流对象
OutputStream os = socket.getOutputStream();
//使用流连接的方式,使用高级流进行数据的写出
OutputStreamWriter osw = new OutputStreamWriter(os);//字符转换流
BufferedWriter bw = new BufferedWriter(osw);
PrintWriter pw = new PrintWriter(bw,true);
/**********下面的内容进行了修改:循环写出**********/
//向服务端发送数据
Scanner scan = new Scanner(System.in);
while(true) {
//不断的可以向服务器端发送消息
String message = scan.nextLine();
pw.println(message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
Server服务器端的start方法进行修改:
/**
* 用于获取输入流对象,并且接收客户端发送的消息
* @param args
* @throws IOException
*/
public void start() {
try {
System.out.println("等待客户端连接...");
/*
* 连接客户端,ServerSocket提供了一个accept接收客户端连接的方法
* accept方法本身也是一个阻塞方法,没有客户端连接时会一直等待客户端连接
*/
Socket socket = serverSocket.accept();
System.out.println("一个客户端连接完毕!!!");
//通过socket实例获取输入流对象
InputStream is = socket.getInputStream();
//流连接进行优化读取数据
InputStreamReader isr = new InputStreamReader(is);//字符转换流
BufferedReader br = new BufferedReader(isr);//缓冲字符输出流
//按行读取数据
//String message = br.readLine();
/**********下面内容进行了修改:循环读入**********/
String message;
while ((message = br.readLine()) != null) {
//打印客户端发送过来的消息数据
System.out.println("服务端接收到客户端发送的消息是:"+message);
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}