大家好,又见面了,我是你们的朋友全栈君。
JAVASocket实现聊天室
文章目录
Sokcet是什么
socket本质上是两个端点之间的通信桥梁,两个端点相互连接,并且打开远程之间的网络IO,从而可以像对本地文件读写一样,JAVA对socket编程有着友好的支持,并且针对客户端和服务端抽象了不同的服务对象
JAVA SOCKET编程中的两个重要对象
JDK对Socket编程抽象了两个类ServerSocket
和Socket
,分别封装了客户端和服务端的基本通信API
ServerSocket
JDK提供的服务端实现,主要用于监听服务端口,并且接受来自该端口的客户端请求,并且生成来自客户端的Socket对象。
几个重要的方法:
构造方法
- ServerSocket()
- ServerSocket(int port)
- ServerSocket(int port,int backlog)
- ServerSocket(int port,int backlog,InnetAddress bindAddr)
上述构造方法设计到大致三个参数,port(端口),backlog请求客户端队列最大长度,bindAddr,将要绑定的IP实现,如果不指定默认本地IP。
accept
public Socket accept() throws IOException
accept方法主要是在开启端口监听之后接受一个客户端的连接请求,如果没有请求进来,那么accept方法会一直阻塞
,直到一个客户端的请求进入,accept方法在接受一个客户端的请求之后,会生成一个客户端的Socket对象,这个对象封装了客户端的IO请求。
Socket client = serverSocket.accept();
//对客户端的输入输出流
OutputStream outputStream= client.getOutputStream();
InputStream inputStream = client.getInputStream();
服务端可通过这个Socket对象获取对客户端的输入流和输出流,这样服务端就可以读取到客户端发送来的的消息,并且可以向客户端发送消息
bind
bind方法是真正实现socket套接字绑定IP和端口的实现,默认在ServerSocket的构造方法中会进行调用。
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
...
try {
bind(new InetSocketAddress(bindAddr, port), backlog);
} catch(SecurityException e) {
close();
throw e;
} catch(IOException e) {
close();
throw e;
}
}
close
当主动调用close方法后,服务器会释放当前绑定的端口,并且自动断开和所有客户端之间的连接,只有主动执行了ServerSocket的close()方法,isClosed()方法才返回true;否则,即使ServerSocket还没有和特定端口绑定,isClosed()方法也会返回false,这是因为服务端内部维护了一个closed变量,初始化为false,只有在调用了close方法才会将closed变量置为true
Socket
JDK提供的Socket套接字实现类,主要封装了端的IO操作,通过Socket对象我们可以实现对客户端及服务端的读写操作
构造方法
Socket(InetAddressaddress, int port);
Socket(InetAddress address,int port, boolean stream);
Socket(String host, intprot);
Socket(String host, intprot, boolean stream);
Socket(SocketImpl impl)
Socket(String host, intport, InetAddress localAddr, Socket(InetAddress address,int port, InetAddress localAddr, int localPort)
ServerSocket(int port);
ServerSocket(int port, intbacklog);
ServerSocket(int port, intbacklog, InetAddress bindAddr)
其中address、host和port分别是双向连接中另一方的IP地址、 主机名和端口号,stream指明socket是流socket还是数据报 socket,localPort表示本地主机的端口号,localAddr和bindAddr是本地机器的地址(ServerSocket的主机地 址),impl是socket的父类,既可以用来创建serverSocket又可以用来创建Socket。count则表示服务端所能支持的最大连接数。
Socket(String host, intprot)
常用的构造方法默认指定host和port,表示要建立的远程连接的服务端IP和端口,在服务端开启端口监听之后,客户端可以得到一个连接到服务端的Socket对象,同时服务端也会得到一个连接到客户端的Socket对象,这样双方可基于Socket实现双向通信,发送并且接受消息
getInputStream,getOutputStream
获取对应端的输入输出流,当双方建立连接后,双方互相持有封装了对方IO操作的Sokcet对象,通过Socket对象获取对应的输入输出流实现双向通信。
close
当客户端的Socket关闭连接时,服务端与客户端的连接自动关闭,但是服务端会继续监听端口,等待新的连接进来。
当服务端的Sokcet关闭连接时,服务端与所有客户端的连接将全部断开,并且释放对应监听接口
聊天室实现
服务端实现
监听端口,调用accept方法等待客户端请求,另外新起两个线程分别针对客户端的读写进行处理
public class Server {
public static final Integer port =80;
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("服务端监听 "+port+" 端口成功!,等待客户端连接");
while (true){
Socket client = serverSocket.accept();
System.out.println("一个新的客户端进来了");
new WriteHelper(client.getOutputStream(),"连接客户端成功!,可以畅所欲言了").start();
new PrintHelper(client.getInputStream(),"服务端").start();
}
}
}
客户端实现
绑定ip和端口,并且启动两个线程分别处理来自服务端的读写
public class Client {
public static void main(String[] args) throws IOException, InterruptedException {
Socket socket = new Socket("127.0.0.1", 80);
new WriteHelper(socket.getOutputStream(),"连接服务端成功!,可以畅所欲言了").start();
new PrintHelper(socket.getInputStream(),"客户端").start();
}
}
针对Socket的输入输出流实现单独线程处理,读写不互相收影响
读线程实现
主要针对Sokcet对象的输入流进行单独处理
public class PrintHelper extends Thread{
private InputStream inputStream;
private String type;
public PrintHelper(InputStream inputStream,String type) {
this.inputStream=inputStream;
this.type=type;
}
public void run() {
byte[] bytes = new byte[1024];
int length;
try {
while (true){
if (((length=inputStream.read(bytes))>1)){
String s = new String(bytes, 0, length);
LocalDateTime nowLocalDate = LocalDateTime.now();
String time = nowLocalDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println(" "+time+" "+type+" : "+s);
System.out.println("____________________________________________");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
写线程实现
主要针对Socket对象的输出流进行单独处理,
public class WriteHelper extends Thread{
private OutputStream outputStream;
public WriteHelper(OutputStream outputStream,String message) {
System.out.println(message);
System.out.println("============================");
this.outputStream=outputStream;
}
public void run() {
Scanner scanner = new Scanner(System.in);
while(true){
String next = scanner.next();
try {
outputStream.write(next.getBytes());
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果
需要先启动服务端,开启端口监听,再启动客户端,实现IP加端口的连接
启动服务端
客户端连接
客户端发送消息
服务端收到消息
服务端回复消息
客户端收到消息
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/148336.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...