1.群聊
客户端
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws Exception {
// 1. 创建Socket对象,并把请求与服务端的端口连接
Socket socket = new Socket("127.0.0.1", 8888);
new ClientReaderThread(socket).start();//启动一个线程来读取服务端的响应
// 2. 从socket通信管道中得到一个字节输出流,用来发送数据给服务端的数据
OutputStream os = socket.getOutputStream();
// 3. 把低级的字节输出流包装成数据输出流
DataOutputStream dos = new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说:");
String msg = sc.nextLine();
// 一旦用户输入了exit,就退出客户端程序
if ("exit".equals(msg)) {
System.out.println("欢迎您下次光临!退出成功!");
dos.close();
socket.close();
break;
}
// 4. 开始写数据出去
dos.writeUTF(msg);
dos.flush();
}
}
}
客户端线程
package com.lzk.test;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class ClientReaderThread extends Thread {
private Socket socket;
public ClientReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream inputStream = socket.getInputStream();
DataInputStream dataInputStream = new DataInputStream(inputStream);
while (true) {
try {
String message = dataInputStream.readUTF();
System.out.println("Server received message: " + message);
} catch (IOException e) {
System.out.println("自己下线了." + socket.getRemoteSocketAddress());
dataInputStream.close();
inputStream.close();
socket.close();
break;
}
}
} catch (IOException e) {
}
}
}
服务端
package com.lzk.test;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
public class server {
public static List<Socket> onLineSocket = new ArrayList<Socket>();
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8080);
// 5. 使用数据输入流读取客户端发送过来的消息
while (true) {
Socket socket = serverSocket.accept();
System.out.println( socket.getRemoteSocketAddress() + "客户端连接成功");
onLineSocket.add(socket);//将客户端的socket添加到在线socket列表中
new ServerReaderThread(socket).start();
}
}
}
服务端线程
package com.lzk.test;
import java.io.*;
import java.net.Socket;
public class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream inputStream = socket.getInputStream();
DataInputStream dataInputStream = new DataInputStream(inputStream);
while (true) {
try {
String message = dataInputStream.readUTF();
System.out.println("Server received message: " + message);
sendMessageToAllClients(message);
} catch (IOException e) {
System.out.println("Server reader thread stopped." + socket.getRemoteSocketAddress());
server.onLineSocket.remove(socket);//从在线列表中移除
dataInputStream.close();
inputStream.close();
socket.close();
break;
}
}
} catch (IOException e) {
}
}
private void sendMessageToAllClients(String message) throws IOException {
for (Socket onLineSocket : server.onLineSocket) {
OutputStream os = onLineSocket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF(message);
dos.flush();
}
}
}
2.实现一个简易的BS架构
只需要开发服务端,不需要开发浏览器。
要求:从浏览器中访问服务器,并让服务器响应一个很简单的网页给浏览器展示,内容是“123456”.
注意:服务器必须给浏览器响应HTTP协议规定的数据格式,否则浏览器不识别返回的数据。
客户端
public class server {
public static List<Socket> onLineSocket = new ArrayList<Socket>();
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8080);
// 5. 使用数据输入流读取客户端发送过来的消息
while (true) {
Socket socket = serverSocket.accept();
System.out.println( socket.getRemoteSocketAddress() + "客户端连接成功");
onLineSocket.add(socket);//将客户端的socket添加到在线socket列表中
new ServerReaderThread(socket).start();
}
}
}
接口
import java.io.*;
import java.net.Socket;
public class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
OutputStream os = socket.getOutputStream();
PrintStream ps = new PrintStream(os);
ps.println("HTTP/1.1 200 OK");
ps.println("Content-Type:text/html;charset=UTF-8");
ps.println(); // 必须换行
ps.println("<div style='color:red;font-size:120px;text-align:center;'>123456</div>");
ps.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.拓展知识
每次请求都开一个新线程在高并发时,容易宕机。
可以使用线程池来改进,代码比上面其实改动不大。
public class server {
public static List<Socket> onLineSocket = new ArrayList<Socket>();
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8080);
ThreadPoolExecutor pool = new ThreadPoolExecutor(
24,
24,
2,
TimeUnit.MINUTES,
new ArrayBlockingQueue<>(8),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
while (true) {
Socket socket = serverSocket.accept();
pool.execute(new ServerReaderRunnable(socket));
}
}
}
实现类
public class ServerReaderRunnable implements Runnable {
private Socket socket;
public ServerReaderRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
OutputStream os = socket.getOutputStream();
PrintStream ps = new PrintStream(os);
ps.println("HTTP/1.1 200 OK");
ps.println("Content-Type:text/html;charset=UTF-8");
ps.println(); // 必须换行
ps.println("<div style='color:red;font-size:120px;text-align:center;'>123456</div>");
ps.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}