Socket
概念
Socket就是JAVA提供给网络编程的一个接口,通过Socket可以让服务器和客户端建立通道,通过套接字Socket获取网络连接中的各种信息,从而实现网络编程
用到的包名是 java.net.Socket 和 java.net.ServerSocket
建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力 ——from 百度百科
连接步骤
架设服务器
- 创建一个ServerSocket对象,并且赋予他占用的端口号
ServerSocket server = new ServerSocket(6666);
- 使用ServerSocket对象的accept()方法等待一个Socket对象连接进来,这个过程如果一直没有客户端连接,程序将会一直在这个位置等待。把接收到的对象用一个Socket保存起来(下一个步骤会和架设客户端的步骤3同步运行)
Socket s = server.accept();
- 创建一个输入流一个输入流。
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintStream ps = new PrintStream(new BufferedOutputStream(s.getOutputStream()));
- 输入输出信息并且关闭流。(输出信息后需要刷新)
String s = br.readLine();
System.out.println(s);
ps.println(“echo:”+s);
ps.flush();
ps.close();
br.close();
架设客户端
- 创建一个Socket对象,赋予主机地址和端口号(自己Debug一下可以发现,代码执行完这一步服务器端就已经接收到连接了)System.out.println(s.getInetAddress().getHostAddress());用于测试接收客户端ip地址
Socket s = new Socket(“localhost”,6666);
- 创建一个输入流一个输入流。
PrintStream ps = new PrintStream(new BufferedOutputStream(s.getOutputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
- 输入输出信息并且关闭流。(输出信息后需要刷新)
ps.flush();
System.out.println(“请输入姓名:”);
sc.nextLine();
String s1 = br.readLine();
System.out.println(s1);
ps.close();
br.close();
到此为止实现了服务器和客户端的单点连接,容易发现服务器代码中现在只支持和单个客户端连接,并不能同时与多个客户端连接,此时就要为服务器端开辟“窗口”,用于接收多个客户端请求,这个“窗口”就是线程池
用线程池实现多点连接
客户端代码不用变,只需要改变服务器端
实现原理就是创建一个线程池,每有一个连接,服务器就创建一个现成用于和客户端连接
- 创建一个线程池(这里为不可变大小线程池)
ExecutorService es = Executors.newFixedThreadPool(3);
- 写一个子线程把创建流后面的步骤都放进子线程中
class clientThread implements Runnable{
Socket s;
public clientThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintStream ps = new PrintStream(new BufferedOutputStream(s.getOutputStream()));
String s = br.readLine();
System.out.println(s);
ps.println(“echo:”+s);
ps.flush();
ps.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
客户端复制粘贴几个出来,在中间写一个Sanner用于防止客户端关闭,同时运行即可。
代码有一个的逻辑问题,问题不影响运行我就没改
控制台有如下输出
服务器已开启,等待连接…
127.0.0.1
你好我是客户端
127.0.0.1
你好我是客户端
127.0.0.1
服务器已满载…无法再接入客户端…
你好我是客户端
这里服务器已满载在你好我是客户端的前面是因为
主线程和子线程同时运行,这里可以通过使用线程等待去改进
对程序本身没影响
完整代码
MultiServer.java
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MultiServer {
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(3);
try{
ServerSocket server = new ServerSocket(6666);
System.out.println("服务器已开启,等待连接...");
int i = 0;
boolean flag = true;
//检测连接数不大于3
while (flag){
i++;
Socket s = server.accept();
System.out.println(s.getInetAddress().getHostAddress()); //获取连接进来的地址
es.execute(new clientThread(s));
if(i==3){
flag = false;
}
}System.out.println("服务器已满载...无法再接入客户端...");
}catch (IOException e){
e.printStackTrace();
}
}
}
class clientThread implements Runnable{
Socket s;
public clientThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintStream ps = new PrintStream(new BufferedOutputStream(s.getOutputStream()));
String s = br.readLine();
System.out.println(s);
ps.println("echo:"+s);
ps.flush();
ps.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client.java
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
try{
Socket s = new Socket("localhost",6666);
PrintStream ps = new PrintStream(new BufferedOutputStream(s.getOutputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
ps.println("你好我是客户端");
ps.flush();
System.out.println("请输入姓名:");
sc.nextLine();
String s1 = br.readLine();
System.out.println(s1);
ps.close();
br.close();
}catch (IOException e){
e.printStackTrace();
}
}
}