第一个版本:可以实现简单的交互,把服务器当做客户
客户端:实现了简单的发送数据到服务器和接收服务器返回的数据
package chat.day_01;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/*
1.创建客户端
2.建立Socket连接
3.接收数据 + 发送数据
*/
public class Client {
Socket client; //定义Socket
BufferedReader reader; //输入流 接收数据
PrintWriter writer; //输出流 发送数据
public void go() throws Exception {
//建立Socket连接
client = new Socket("localhost",7777);
while (true){
//控制台输入数据
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
//发送数据
writer = new PrintWriter(client.getOutputStream());
writer.println(console.readLine());
writer.flush();
//接收数据
reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
String msg = reader.readLine();
System.out.println(msg);
}
}
public static void main(String[] args) throws Exception {
new Client().go();
}
}
服务器:把客户端发来的数据保存,然后发给客户端
package chat.day_01;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/*
1.创建服务器 指定端口
2.接收客户端连接
3.发送数据 + 接收数据
*/
public class Server {
ServerSocket server; //定义Socket
BufferedReader reader; //输入流 接收数据
PrintWriter writer; //输出流 发送数据
public void go() throws Exception {
//建立ServerSocket连接
server = new ServerSocket(7777);
//接收客户端连接 阻塞式
Socket socket = server.accept();
while (true){
//接收数据 输入流
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg = reader.readLine();
//发送数据 输出流
writer = new PrintWriter(socket.getOutputStream());
writer.println("服务器--->" + msg);
writer.flush();
System.out.println(msg);
}
}
public static void main(String[] args) throws Exception {
new Server().go();
}
}
客户端控制台:显示服务器发回来的数据
服务器控制台:显示客户端发来的数据
刚开始有一个问题:就是只可以交互一次,后来发现是因为
while (true){ //接收客户端连接 阻塞式 Socket socket = server.accept();}
我把serve.accept();放在了死循环中,serve.accept();是阻塞式的,只有当一个客户端连接后才会执行后的代码。
这个版本服务器只能先读取再发送,客户端只能先发送再读取,输入流和输出流一个线程中。
第二个版本: 把客户端的输入输出流进行了封装并使用了多线程
客户端:
package chat.day_02;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/*
1.创建客户端
2.建立Socket连接
3.接收数据 + 发送数据
*/
@SuppressWarnings("all")
public class Client {
Socket client; //定义Socket
public void go() throws Exception {
//建立Socket连接
client = new Socket("localhost",9999);
new Thread(new Send(client)).start();
new Thread(new Receive(client)).start();
}
public static void main(String[] args) throws Exception {
new Client().go();
}
}
服务器:
package chat.day_02;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/*
1.创建服务器 指定端口
2.接收客户端连接
3.发送数据 + 接收数据
*/
public class Server {
ServerSocket server; //定义Socket
BufferedReader reader; //输入流 接收数据
PrintWriter writer; //输出流 发送数据
public void go() throws Exception {
//建立ServerSocket连接
server = new ServerSocket(9999);
//接收客户端连接 阻塞式
Socket socket = server.accept();
//接收数据 输入流
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//发送数据 输出流
writer = new PrintWriter(socket.getOutputStream());
while (true){
String msg = reader.readLine();
writer.println("服务器--->" + msg);
System.out.println(msg);
writer.flush();
}
}
public static void main(String[] args) throws Exception {
Server server = new Server();
server.go();
}
}
send:发送数据
package chat.day_02;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/*
发送数据线程
*/
public class Send implements Runnable {
private PrintWriter writer; //输出流 发送数据
private BufferedReader console; //控制台输入流
//初始化
public Send(Socket client){
//控制台输入数据
console = new BufferedReader(new InputStreamReader(System.in));
try {
//发送数据
writer = new PrintWriter(client.getOutputStream());
writer.println(console.readLine());
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
//从控制台接收数据
private String getMsgFromConole(){
try {
return console.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
/*
1.从控制台接收数据
2.发送数据
*/
public void send(){
//接收控制台输入数据
String message = getMsgFromConole();
if((null != message) && !(message.equals(""))){
//发送数据
writer.println(message);
writer.flush();
}
}
@Override
public void run() {
while (true){
send();
}
}
}
receive:接收数据
package chat.day_02;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/*
接收数据线程
*/
public class Receive implements Runnable {
private BufferedReader reader; //输入流 接收数据
public Receive(){
}
//使用带参构造器初始化
public Receive(Socket client){
String msg = null;
try {
//接收数据
reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
msg = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(msg);
}
/*
接收数据
*/
public String receive(){
String message = "";
try {
message = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return message;
}
@Override
public void run() {
while (true){
System.out.println(receive());
}
}
}
问题:
1.刚开始就是if((null != message) && !(message.equals("")))中 !(message.equals("")写成了 (message.equals(""),导致只能交互一次;
2.不能创建多个客户端(我也不知道原因);
3.不能多个客户端共同聊天,只能等一个停止后另一个才能聊天。
第三个版本:服务器使用了多线程,多人聊天,使用ArrayList来存储客户端发送的消息,并发给其他用户。 只修改了服务器
服务器:
package chat.day_03;
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.Iterator;
/*
1.创建服务器 指定端口
2.接收客户端连接
3.发送数据 + 接收数据
*/
public class Server {
ServerSocket server; //定义Socket
private ArrayList<Object> list = new ArrayList<>(); //使用集合存储消息
public static void main(String[] args) throws Exception {
new Server().go();
}
public void go() throws Exception {
//建立ServerSocket连接
server = new ServerSocket(9999);
//接收客户端连接 阻塞式
Socket socket = server.accept();
//一条路
MyChannnel channnel = new MyChannnel(socket);
//把数据加到集合中
//启动线程
new Thread(channnel).start();
}
/*
一个客户一条路
*/
private class MyChannnel implements Runnable{
private BufferedReader reader; //输入流 接收数据
private PrintWriter writer; //输出流 发送数据
//使用带参构造器初始化流
public MyChannnel(Socket socket){
try {
//接收数据 输入流
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//发送数据 输出流
writer = new PrintWriter(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
//接收数据
private String receive(){
String message = null;
try {
message = reader.readLine();
list.add(message);
System.out.println(message);
} catch (IOException e) {
e.printStackTrace();
list.remove(this); //移除自身
}
return message;
}
// //发送数据
// private void send(String message){
// if((null != message) || (message.equals("")))
// return;
// writer.println("服务器--->" + message);
// writer.flush();
// }
//发给其他客户端
private void sendOthers(String message) {
//拿到list迭代器对象
Iterator it = list.iterator();
while (it.hasNext()){
//自己不接受自己发的消息
//if(message == it.next())
// continue;
try{
writer.println("服务器--->" + it.next());
writer.flush();
}catch (Exception e){
e.printStackTrace();
}
}
}
@Override
public void run() {
while (true){
sendOthers(receive());
}
}
}
}
加入
if(message == it.next()) continue;
就可以不接受自己发的消息。
总结:
通过这个简单的项目,对线程和网络的知识点进行了巩固,其中还存在很多问题,我会继续改善,也会试着用界面去实现。