socket实现人多聊天与Java代码加载过程
第一部分是java代码加载过程
关于java代码加载过程,今天调试了阿里巴巴一份代码,如下:
/** * 加载方法不等于执行方法,初始化变量则会赋值 * 类加载顺序应为 加载静态方法-初始化静态变量-执行静态代码块 * 实例化时 先加载非静态方法-实例化非静态变量-执行构造代码块-执行构造函数 * @author panteng * */ public class StaticTest { /**第一个加载*/ public static int k = 0; /**第二个加载,因为是new一个实例, * 首先初始化j 打印出 1:j i=0 n=0 * 执行构造块 打印出 2:构造快 i=1 n=1 * 执行构造方法 打印出 3:t1 i=2 n=2 * 实例化完成 */ public static StaticTest t1 = new StaticTest("t1"); /**第三个加载 过程同上 * 首先初始化j 打印出 4:j i=3 n=3 * 执行构造块 打印出 5:构造快 i=4 n=4 * 执行构造方法 打印出 6:t2 i=5 n=5 */ public static StaticTest t2 = new StaticTest("t2"); /**第四个加载 * 打印出 7:i i=6 n=6 */ public static int i = print("i"); /** * 第五个加载 */ public static int n = 99; /** * 此变量在类加载的时候并不初始化,在实例化类的时候初始化 */ public int j = print("j"); { print("构造快"); } /** * 第六个加载 此时,n已经被初始化 所以打印出 * 8:静态块 i=7 n=99 */ static{ print("静态块"); } //-----------以上属于类加载--------------------- /** * 实例化过程: * 首先加载非静态方法集; * 初始化非静态变量:9:j i=8 n=100 * 执行构造块:10:构造快 i=9 n=101 * 执行构造方法:11:init i=10 n=102 * 实例化完成 */ /** * 执行构造函数 实例化完成 * @param str */ public StaticTest(String str) { System.out.println((++k) + ":" + str + " i=" + i + " n=" + n); ++n; ++i; } /** * 这个应该是最先加载 但是,加载不等于执行 * 因为如果不加载此函数,静态变量是无法初始化的 * @param str * @return */ public static int print(String str) { System.out.println((++k) + ":" + str + " i=" + i + " n=" + n); ++i; return ++n; } public static void main(String[] args) { StaticTest t = new StaticTest("init"); } }
首先加载类,然后实例化:
类加载过程:
首先加载所有的静态方法,但不执行;
然后按照静态变量的顺序开始初始化
静态变量初始化完毕后执行静态构造块(不执行构造块)
此时类加载完毕
实例化过程:
加载非静态方法
初始化非静态变量
执行构造代码块
执行构造函数
此时实例化完毕
第二部分是socket实现多对多的群聊
代码部分跟昨天实现一对一的变化主要在服务器这端,在服务端使用List集合来保存一组socket,每当有一个客户端向服务端发送socket时,
都会将这个socket加入到数组列表中,然后开启一个新的线程来为这个客户端群发消息。介于昨天使用BufferInputStream的readLine方法出
现了换行问题,今天直接使用字节来传输消息,InputStream的方法read(byte[] b)方法可以将读到的数据传到字节数组中,并且返回字节
数组的长度,int len = in.read(b),然后将字节数组转换成字符串,String str = new String(b,0,len);输出的时候也不一定使用
PrintWriter方法,可以直接使用socket.getOutputStream()返回的OutputStream来发送数据,注意前者PrintWriter是使用print,后者
OutputStream是使用write方法。
e.g: out.print(str);
e.g: out.write(str.getByte());
传输方法跟昨天的有所不同,以及服务端的改动,我还是讲客户端和服务端的代码发一遍。
客户端:
import java.net.*; import java.io.*; import java.util.Scanner; public class Client { public static String sg ;//客户端用户名 public Client() { try { Socket socket = new Socket("127.0.0.1", 4800); System.out.println("客户端已经开启----"); System.out.println("请取您的用户名"); Scanner scanner = new Scanner(System.in); sg=scanner.next(); new Thread(new Output(socket)).start(); new Thread(new Input(socket)).start(); } catch (Exception e) { e.printStackTrace(); } } class Input implements Runnable { Socket socket; public Input(Socket socket) { this.socket = socket; } public void run() { while (true) { try { InputStream in = socket.getInputStream(); byte[] b = new byte[1024]; int len = in.read(b); String str = new String(b, 0, len); System.out.println(str); } catch (IOException e) { e.printStackTrace(); } } } } //输出信息到服务端 class Output implements Runnable { Socket socket; public Output(Socket socket) { this.socket = socket; } public void run() { try { Scanner scanner = new Scanner(System.in); while(true) { OutputStream out = socket.getOutputStream(); String str = sg+":"+scanner.next(); out.write(str.getBytes()); } } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { new Client(); } }
服务端代码:
import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; public class Server { List<Socket> list = new ArrayList<Socket>();//将收到客户端的socket添加到数组列表 public Server() { try { ServerSocket serverSocket = new ServerSocket(4800); System.out.println("服务端正在等待客户端请求......"); while (true) { Socket socket = serverSocket.accept(); new Thread(new Output(socket, list)).start(); list.add(socket); } } catch (IOException e) { e.printStackTrace(); } } class Output implements Runnable { Socket socket; List<Socket> list; public Output(Socket socket, List<Socket> list) { this.socket = socket; this.list = list; } public void run() { try { while (true) { InputStream in = socket.getInputStream(); byte[] b = new byte[1024]; int len = in.read(b); String str = new String(b,0,len); list.remove(socket);//每次群发消息不发给发送给服务器的一方客户端 for (Socket s:list){ OutputStream out = s.getOutputStream(); out.write(str.getBytes()); } list.add(socket); } } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { new Server(); } }
以及今天无意间看到了关于线程的生命周期,权当复习一下:
总结
今天不是第一次使用socket了,遇到的问题不像昨天那么多,但是还是有很大一部分的问题,socket编程,关于TCP与UDP方面的通讯,现在还没有进行尝试,还有同一个局域网和不同网络方面的问题,学习还是需要一步步的来,不能一口吃撑胖子,今天也挺有收获的,了解了java加载类方面的知识,感觉在类实例化前,就先初始化了静态变量和方法,在以后的学习中可能会有用;实现了类似QQ群聊的功能,如果想多写点,我觉得既然有群聊,在群聊的基础上我还可以写个聊天室里一个用户对另一额用户的私聊,私聊方面现在思路基本就是,当客户端输入私聊+ID名,剩下的基本就是跟一对一一样的。