前言
面试的时候面试一个比较印象深刻的问题就是,有没有接触过SOCKET编程.虽然知道往后的linux课程中应该会接触到,但是等不及了,先自行操刀了.
一、敏捷开发计划游戏
二、代码
服务器端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import static java.lang.Thread.sleep;
public class Server extends ServerSocket {
final static int SOCKET_PORT = 9999;
List<Message> messages = new LinkedList<>();
List<ClientThread> clientThreads = new ArrayList<>();
public static void main(String[] args) throws IOException {
new Server();
}
public Server() throws IOException {
super(SOCKET_PORT);
//创建一个线程,当消息队列满6个,即六个人都发了计划点数后,向每个socket线程发送6个人的点数
new Thread(() -> {
while (true) {
int size = messages.size();
if (size > 5) {
for (Message message : messages)
for (ClientThread clientThread : clientThreads) {
clientThread.sendMessage(message);
}
messages.clear();
}
else {
try {
//没到六个人发送时,释放cpu资源
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
while (true) {
Socket client = accept();
clientThreads.add(new ClientThread(client));
}
}
class ClientThread extends Thread {
BufferedReader in;
PrintWriter out;
String username;
public ClientThread(Socket client) throws IOException {
out = new PrintWriter(client.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out.println("已连接服务器,请输入您的姓名:");
username = in.readLine();
out.println(username+"你好!");
System.out.println(username+"已经连接");
start();
}
@Override
public void run() {
String line;
try {
while (true) {
//接收信息,并添加到消息链表中
line = in.readLine();
if (line != null) {
messages.add(new Message(username, line));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMessage(Message message) {
out.println(message);
}
}
}
//消息类
class Message {
String name;
String msg;
public Message(String name, String msg) {
this.name = name;
this.msg = msg;
}
@Override
public String toString() {
return name + ":" + msg;
}
}
客户端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class ClientSocket extends Socket {
static final int SERVER_PORT = 9999;
static final String SERVER_IP = "127.0.0.1";
public static void main(String[] args) throws IOException {
new ClientSocket();
}
public ClientSocket() throws IOException {
super(SERVER_IP, SERVER_PORT);
PrintWriter out = new PrintWriter(getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream()));
Scanner sc = new Scanner(System.in);
new Thread(() -> {
try {
while (true) {
String line = in.readLine();
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
while (true) {
String line = sc.nextLine();
out.println(line);
}
}
}
三、总结
涉及到的知识:
- IO流 字节流、字符流 控制流 打印流
- Socket编程反而挺简单的,设置好端口进行连接即可
- 多线程
四、缺陷
- 线程不安全问题没有仔细解决
- 流没有关闭
- 没有设置正常退出
五、大坑
有个坑想不通.在服务器端发消息的线程中.如果我把else部分注释到,程序就没法运行了.当消息超过六条也不会发送消息.
更神奇的是,如果我debug模式下,超过六条后服务器端还是不会有反应.但是我把断点打到线程内后,程序就立刻执行到断点处.点击继续运行,程序正常向客户端发送消息.
猜测:单纯线程会抢占不到CPU资源?怪怪的,待解答
new Thread(() -> {
while (true) {
int size = messages.size();
if (size > 5) {
for (Message message : messages)
for (ClientThread clientThread : clientThreads) {
clientThread.sendMessage(message);
}
messages.clear();
}
/*
else {
try {
//没到六个人发送时,释放cpu资源
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
*/
}
}).start();