闲暇之余好久没写Socket的网络程序了,最近闲下来,写了一个小demo,觉得是一个非常不错的用来练习IO流和Socket,和GUI的一个小程序.
由于是聊天窗口的对话,我分别建立了一个客户端的class文件和服务器端的class文件,一个用来输入文字信息,向服务器端发送信息用DataOutputStream的writeUTF方法,在服务端的class文件中,接受客户端发来的信息用DataInputStream的readUTF方法, 服务端另外在把存进来的信息发给另一个客户端用DataOutputStream的writeUTF方法,另外的客户端在收到信息用DataInputStream的readUTF方法,这里都采用了读或写一个字节的方法来处理,其中服务端抓取要发送的客户端,用到了集合类,发送的过程我用了线程来处理,同理在客户端接受的时候也用了一个线程来处理,下面我给出这个小demo的具体简单步骤:,
Chat 1
第一个版本用来画出聊天的窗口: 步骤为基本的窗口方法和Window 窗体,采用继承Fram窗体的方法来绘制 ,并把绘制方法定义到public void launch()中,在主函数中进行调用 !
Chat 2
第二个版本用来画出聊天窗口的精准布局,步骤为在main函数为声明TF,TR等成员变量,在调用两次 add()方法分别加到窗体的南和北
其基本用来区分输入和显示
Chat 3
第三个版本用WindowListener窗口监听关闭窗口步骤是this.WindowListener(new WindowAdapter());用匿名类来实现窗窗体的关闭,里面调用System.exit(0)来实现窗口的关闭
Chat 4
第四个版本用ActionListener按回车,文本框的监听来返回到TextArea()中其中类的实现用内部类实现;步骤为tf.addActionListener(new MO()),
在声明 private class MO implements ActionListener(){}重写actioPerformed()方法来加入字符串同步
Chat 5第五个版本用Server新建服务端,new ServeSocket(8888)对象, while 循环{客户端接受 Socket =ss.acpet(),进行语句调试Ssys("连接成功")!}
Chat 6第六个版本在客户端 进行连接Server,窗口新建,自动连接成功在 setVisible()后 (调用connect()方法), 步骤为单独建一个方法 public void connect(),{Socket (127.0.0.1,8888); 连接上用SYS("连接上了")};
调用在方法后面直接调用
Chat 7 在actionPerform的方法中发到服务端中->
在客户端中
1.Socket s=null;改为成员变量(main方法外),
将Socket暴露出来,发送字符串
2.new Dataoutpustream(s.getOutputStream)-->在actionPerform()方法中
3.写字符串dos.writeUTF(str),dos.flush(),dos.close;
在服务器端
1.在While循环中进行new DataInputStream(s.getInputStream());
2.String str=dis.readUTF(),SYS(str);dis.close();
Chat 8会出现的错误 (开启里两个错误,端口号绑定错误,地址已启用监听异;常见的错误2,空指针错误 原因是Socket变量重定义,初始变量为null在这个过程中进行程序的打印调试)中的步骤 :
在客户端
1.将DataoutputStream 声明为成员变量
2.在connect()方法中之后在127下面的语句中进行dos 的初始化;
3.清理资源的方法disconnect() dos.close();s.close();
4.在窗口关闭之前disconnect();
在服务器端
1.声明started <-进行修改用while(started){readUTF();}
2.建立布尔变量局部变量 start=false;
3.连接建立后 start=true; while(startt){.bbc=f.....bc=tr....new DataInputStream()};
4.子层循环 while(bv){str=redUTF;SYS(STR);}
Chat 9第九个版本在 服务端:1.在ss后面catch(IOE)catcht(BINDE){SYS("端口使用中")}; try {while(started)t}catch(EOF){SYS("客户端关闭");注释掉e.printstackprint()-->Sys("客户端关闭" ;
2.定义ServerSocket,Socket,DataInputStream为局部变量
3. finally { try-- if(dis!=null) dis.close(),if(s!=null)s.close()--catch(IOE)};
Chat10第十个版本
服务器端:Socket ,DIS,SS,改为成员变量(main方法外)端口使用中->sys(请关掉程序重新运行服务器) ->sys.exit
1.新建一个线程类在Server中建立相应的服务
class Client implements Runnable
{private Socket s; private DataInputStream dis=null; 布尔变量 bonnect =false}->
3.(重写run方法)void run ->run()
{放入你要处理的方法 try{while(beconnect); str=utf sys(str)}catch{IOE}}
finally { ss.close(); -<
4.public Clinent(构造方法 Socket s) this.s=s,dis=s.getInputStream;bonnect =true ;
取消掉成员变量中的Socket ;在SYS("连接成功")后Clinent c=new Clinent();new Thread(c).start();} 修改ServerSocket start为成员变量;
5.定义public void start(){放入main中所有的方法}main中 调用 new ChatServer.start();
Chat11第十一个版本 在服务端中进行修改,
1.定义成员变量list
2.在Thread(c).start()-->clients.add(c);
3.class 内部类中DataOutputstream dos =null;
dos在dis下进行初始化,{在class 内部类 中 }
定义public void send(String str) dos.writeUTF(STR);
5.在run 中 for(int i=0;i
c.send(str);
Chat12 第十二个版本 在客户端:
1.起一个单独的线程private class RecThread implements Runnable{ }-->重写run方法 ;在run方法中 try{while(bConnect)<--private bConnect=false; String str=dis.redUTF();SyS(str);tr.setText(tr.getText()+str+'\n');}catch(IOE){} ;
2.调用connect()方法 下启动新的线程 Thead->new Thead(new RecvThead()).start(); //tr.setText
TextArea -> Thread tRect=new Thread(new RecThearac()); ->! finally { try {dos.close()dis.close(),s.close();}}
disconnect()->>try {dos.close();dis.close();s.close()}
Chat13第十三个版本
在服务端中Send方法中在try{dos.writeUTF(STR)}中把相关的clinet在List中去catch(IOEXception e) clients.remove(this);<---Sys("一个客户端退出");
这个是用哪个Clined端里面的函数图,Server端的程序图其主要核心在启了另一个线程
以下程序有仍有很多小bug希望,各位在实践运行的时候能加以修缮
这个是源码的地址https://download.csdn.net/download/zgz102928/10819813