Edgar--java学习--多线程聊天室的实现(v1.0)(和我一样的小白分享)

首先这是一个很初级,但是很好懂的、基于java-socket实现的聊天室。但是代码还未封装成型,以及其他待改善的地方,先记录一波。

网络编程的本质和现状

首先java的网络编程基本已经没有市场了。。。但是这是一个很基础的,也为了理解计网或者是后期项目打的基础的。总体也有点锻炼业务思路。
网络编程这块,在计网中,你首先得了解 IP 与 端口这两个名词,好比你家地址和具体的屋里的门,这样到你家以后才能找到你,而不是你爸或者隔壁老王。
socket的思路就c/s模式,客户端模式里面我没有使用线程,服务端我们使用多线程(实际操作系统和实际项目也是这样的,因为你不能只是服务一个程序)(说到操作系统,我觉得理解一下网络编程对于系统和计算机网络都有好处)(这块还涉及到osi5层模型,socket在传输层与应用层之间)(先说到这,到时候我联系一下计网笔记再聊)

写的过程中的思路过程

当我知道这个需求的时候,一开始我是上来就想多进程的。我理解的过于简单,就知道来一个客户端就建立一个线程,too young。。后面的话,我先实现单线程的连接,然后了解到其实客户端的socket才是一个桥梁。理解了这个东西以后,在哪里多线程就清楚多了。另外注意的点是输入输出流的细节,一定要flush,请注意我说的是flush不是close
因为你close的时候会顺带着把从客户端的socket的连接一并断掉,显然你不想。。下面是直接close报的错误
java.net.SocketException: Socket is closed

一、实现多线程的过程

我找了很多视频,代码发现确实功能都太多了,不利于理解本质。然后我自己就从单线程开始搞。搞这部分主要的理解在于,理解不管是客户端还是服务端 我们都要通过与客户端相连的socket来发送消息(好像是废话)

//向服务端发送消息
OutputStream out=clientSocket.getOutputStream();
// 接受客户端发来的消息	 
in = clientSocket.getInputStream();

所以我们从这个角度分析,我们接到一个accept监听来的客户端的socket就建立一个线程。有了这个想法以后我们就准备把socket放进多线程里面
我们知道run()不能让我们直接调用。我们实现一个线程类,我们把这个socket放进有参构造器里面,实现传参调用。

class ServerThread implements Runnable {
	//记录--客户端序号
	private int num;
	private Socket clientSocket;
	public ServerThread(Socket clinet,int num) {
		this.clientSocket = clinet;
		this.num=num;
	}

二、具体的输入输出流

详情见代码思路,多试试才是王道

三、代码分析和后续优化

发现,客户端和服务端的接受与发送代码冗余度100%,后期准备封装方法。

三、上代码

客户端

package Homework11;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
import java.util.zip.InflaterInputStream;

public class Client {
	
public static void main(String[] args) throws Exception{
	Socket clientSocket=new Socket("localhost", 8889);
	//1.---------客户端发送消息部分
	while (true) {
	Scanner  scanner=new Scanner(System.in);
	String string="我是客户端::::::";
	//输入端的自定义的消息
	System.out.println("请客户端输入消息");
    String DIYdata=scanner.next();
	//向服务端发送消息
	OutputStream out=clientSocket.getOutputStream();
	//转换流
	OutputStreamWriter osw=new OutputStreamWriter(out);
	osw.write(string);
	osw.write(DIYdata);
	//必须关闭不然消息带不走
	osw.close();	
	//2.---------客户端接受消息部分
	InputStream in = null;
	// 准备输出流一会接受客户端发来的消息
	try {
		in = clientSocket.getInputStream();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	char[] data = new char[1024];
	InputStreamReader isr = new InputStreamReader(in);
	try {
		isr.read(data);
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	StringBuffer sb = new StringBuffer();
	sb.append(data);
	// 输出服务端数据
	System.out.println(sb.toString());
	}
}
}

服务端

package Homework11;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

//字节流变成字符流
public class SeverSocket {
	//记录--客户端序号
	static int num = 0;
	public static void main(String[] args) throws Exception {
		// 客户端数目
		
		ServerSocket serverSocket = new ServerSocket(8889);
		System.out.println("服务端已启动");
		// sock---客户端的socket
		while (true) {
			Socket clientSocket = serverSocket.accept();
			num++;
			System.out.println("第" + num + "个客户端已经启动");
			Thread thread = new Thread(new ServerThread(clientSocket,num));
			thread.start();
		}
	}
}

class ServerThread implements Runnable {
	//记录--客户端序号
	private int num;
	private Socket clientSocket;
	public ServerThread(Socket clinet,int num) {
		this.clientSocket = clinet;
		this.num=num;
	}

	@Override
	public void run() {
		// 客户端进来的消息
	   while (true) {
		InputStream in = null;
		// 准备输出流一会接受客户端发来的消息
		try {
			in = clientSocket.getInputStream();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		char[] data = new char[1024];
		InputStreamReader isr = new InputStreamReader(in);
		try {
			isr.read(data);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		StringBuffer sb = new StringBuffer();
		sb.append(data);
		// 输出客户端数据
		System.out.println("第" + num + "个客户端输出");
		System.out.println(sb.toString());
		
		// 服务端发给客户端的消息
		//准备好输出流
		OutputStream out = null;
		System.out.println("服务端请输入:::");
		try {
			out = clientSocket.getOutputStream();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//转换成字符流
		OutputStreamWriter osw=new OutputStreamWriter(out);
		Scanner scanner=new Scanner(System.in);
		String vlog="我是服务端::::::";
		String  serverdata=scanner.next();
		try {
			osw.write(vlog);
			osw.write(serverdata);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			osw.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	}

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值