Socket
1.概述
-
Socket
编程又叫 套接字编程。- 套接字,即使用TCP提供了两台计算机之间的通信机制 。
-
怎么通讯的呢!? 客户端程序 创建一个套接字,并尝试连接 服务器 的套接字。当连接建立时,服务器会创建一个Socket对象。客户端和服务器现在可以通过对Socket对象的 写入和读取(I/O) 来进行通信。(简单理解为,两边都要有socket,都通过socket进行通信)。
- Socket 简单理解: 网络编程相当于 Ip地址与端口和协议(底层很多种,泛指Tcp,ip)的组合。 使其多台计算机在通过
socket
进行通信。
- Socket 简单理解: 网络编程相当于 Ip地址与端口和协议(底层很多种,泛指Tcp,ip)的组合。 使其多台计算机在通过
-
举一个例子:
- 应用程序,如QQ,它产生的聊天数据是通过这样的
Tcp/ip协议
进行传输的,但是QQ 不会 直接和传输协议建立联系,而是能把应用程序和传输协议之间连接起来的桥梁,这个桥梁就是所谓的socket
1. 查看套接字的命令: netstat 是用于显示套接字内容的命令,-ano 选项表示以下的意思: a:不仅显示正在通信的套接字,还显示包括尚未开始通信等状态的所有套接字 n:显示 IP 地址和端口号 o:显示使用该套接字的程序 PID 2.注意:端口号有 0~65535 其中0-1024是被占用的。
- 应用程序,如QQ,它产生的聊天数据是通过这样的
其中第4和5说明:
4.状态:
State,表示通信状态。
LISTENING:等待对方连接的状态
ESTABLISHED:完成连接并正在进行数据通信的 状态
CLOSE WAIT:表示被动关闭
SYN_SENT:是三次握手的过程,表示你的机器发 起了连接,对方没有响应
TIME WAIT:等待足够的时间以确保远程 TCP 接收到连接中断请求的确认
5.pid:进程的标识符。
2. 服务器
2.1 ServerSocket
-
java.net.ServerSocket
服务器端需要的类,在服务器端开启一个端口号,然后侦听客户端的请求。1.构造方法: ServerSocket(int port) 创建绑定到指定端口的服务器套接字。 2.常用方法: Socket accept() 侦听要连接到此套接字并接受它。 void close() 关闭套接字。 3.操作:启动服务。 ServerSocket ss = new ServerSocket(端口号); 等待客户端发起连接,连接后会建立起通道:Socket socket = ss.accept(); 侦听
3. 客户端
3.1 Socket
-
java.net.Socket
类代表客户端和服务器都用来互相沟通的套接字,并通过io流操作。- 客户端要通过实例化获取一个
Socket
对象,而服务器则通过accept
方法的返回值获得一个Socket
对象。
1.构造方法: Socket(String host,int port) 创建一个流套接字,并将其连接到指定主机上的指定端口号。 2.常用方法: InputStream getInputStream() 返回此套接字的输入流。 OutputStream getOutputStream() 返回此套接字的输出流。 void close() 关闭此套接字。 3. 操作:新建Socket对象,连接指定IP指定的端口。 Socket s = new Socket(IP,port); 从Socket获取双向的流: InputStream in = s.getInputStream(); OutputStream out = s.getOutputStream();
- 客户端要通过实例化获取一个
4. 入门案例
4.1 服务器端创建
- 接受客户端发来得数据,并服务端响应返回数据。
- 注意启动顺序:先启动
Server
在启动Client
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*1.创建服务器端,用来接受客户端请求。
- 启动服务器。
- 开始监听客户端。
*/
public class Test_Server {
public static void main(String[] args) throws Exception{
//1.创建服务器 ,
ServerSocket server = new ServerSocket(8200);//端口号选择需要注意。0-1024被占用.
//2.接受
Socket socket = server.accept(); //监听客户端请求。
//3.接受客户端请求数据
InputStream in = socket.getInputStream();
//3.1 输出结果。
int b;
for (int i = 0; i <5 ; i++) {
System.out.println((char)(b=in.read()));//字节转换字符
}
//4.给客户端返回信息
OutputStream out = socket.getOutputStream();
out.write("world".getBytes());
out.flush();
server.close();
}
}
4.2 客户端创建
- 注意关流顺序,如果提前关闭会报错
Socket is closed
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/* 1.创建客户端,需要指定连接的服务器
2.给服务器发送数据
*/
public class Test_Client {
public static void main(String[] args) throws Exception{
//1.创建客户端
Socket socket = new Socket("127.0.0.1",8200);
//2.向服务器发送数据,先获取输出流。
OutputStream out = socket.getOutputStream();
//out.write("你好".getBytes()); //需要转码
out.write("hello".getBytes());
//3关闭资源
//out.close(); //由于提前关闭资源,Socket is closed 报错
out.flush();
//4接受服务器返回的数据
InputStream in = socket.getInputStream();
int b ;
for (int i = 0; i <5 ; i++) {
System.out.println((char)(b=in.read())); //字节转换字符
}
socket.close();
}
}
5. 案例: Socket 回声案例
- 场景: 需要服务器创建多个连接。 如同: 生活中,给客服中心打电话,每一个客户会对应一个客户(相当于只有一个客户中心,会分配多个客户人员去解决客户端问题)。
- 客户端发送数据,客服回复数据。
5.1 服务器端
- 重点在服务器端开发,需要注意如何处理多个客户端请求问题。
- 如何分配“客服”解决每个客户端的io问题。
/**
* 1.启动服务器
* 2.连接客户端
* 3.创建服务器的话务员,给每一个客户端配一个"客服";
* 作用: 客服负责和客户端的io连接。
*/
public class Server {
public static void main(String[] args) {
//启动服务
new Server().service();
}
//创建方法,负责多个客户端。123的处理。
public void service(){
//内部类,主要负责客户端的监听。
class MyThread extends Thread{
@Override
public void run() {
try {
//启动服务器
ServerSocket serverSocket = new ServerSocket(8200);
System.out.println("启动服务器成功");
//1.如果是多客户端连接,就需要多个监听
//Socket socket = serverSocket.accept();
while (true){//通过循环拿到多个连接监听
Socket socket = serverSocket.accept();
System.out.println("连接客户端成功");
//2.分配"每一个客户端多应的客服",多线程。
FuWuThread t = new FuWuThread(socket);
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//2.1 注意:启动客服服务
new MyThread().start();
}
//3.创建内部类“客服”。作用负责io的沟通。(只为Server服务)
class FuWuThread extends Thread{
//3.1 将所有数据保存在socket上,获取流(负责读写),但是如何获取Socket!?
Socket socket;
//通过含参数构造方法;
public FuWuThread(Socket socket){
this.socket=socket;
}
//4.重写run()并接受客户端传来得数据。
@Override
public void run() {
//改造一下使用高效包装,通过转换流 InputStreamReader 把字节转换为字符。
try {
//socket编程中一定要用printWriter去写。不能使用BufferWirter。
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(
new OutputStreamWriter(socket.getOutputStream()));
//读取客户端发来数据。
String line;
while((line = in.readLine()) != null) {//只要有数据就一直读
System.out.println("客户端发来的数据:"+line);
//可以给客户端作出响应-接收键盘输入的响应
System.out.println("回复的消息:");
String input = new Scanner(System.in).next();
//发出作为服务器的响应
out.println(input);
out.flush();//只要是输出,就需要刷新数据。
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
5.2 客户端
- 客户端连接相对简单,只需要循环,读和写即可。
public class Client {
public static void main(String[] args) {
//1.创建客户端,并指定ip和端口
try {
Socket socket = new Socket("127.0.0.1", 8200);
System.out.println("连接成功");
//2.循环发送信息
while (true){
PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//3.输出
System.out.println("发送给服务器信息:");
String input = new Scanner(System.in).next();
out.println(input);//向服务端发送指定数据
out.flush();//把数据刷出去
String line = in.readLine();//读取回声数据
System.out.println("服务器相应:"+line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}