通信最基本的也就是一个输入流一个输出流,InputStream 和 OutputStream 。这样一开始我们写了一个最基本的服务器接着一步一步实现功能。
1、就实现一个简单的服务器,可以跟系统的最简单的客户端进行聊天
java.net.ServerSocket ss=new java.net.ServerSocket(8888);
java.net.Socket s=ss.accept();
//输出流
java.io.DataOutputStream ds=new java.io.DataOutputStream(s.getOutputStream());
//输入流
java.io.DataInputStream di=new java.io.DataInputStream(s.getInputStream());
String sss="你好、、、、";
ds.write(sss.getBytes());
int t=di.read();
while(t!=13){
System.out.println(t);
t=di.read();
}
s.close();
只是简单的包括一个输入流一个输出流,在输出流中把自己传的内容构成的byte数组传过去。读入的话就一次读一个字节,当为回车键时停止。
2、我可视化了这个服务器,添加了一个创建服务器按钮,在点击这个按钮时先取得输入框中的你输入的端口号值,创建ServerSocket对象,并且在这里启动一个输入流的线程,这就意味着创建服务器的同时就可以接收客户端发来的值,并且把这个值setText到界面上。发送按钮就是先取得界面上用户输入的值,再把它写出去。最后的关闭按钮就是关掉每个线程的输入输出流。
if("创建".equals(e.getActionCommand())){
String sl=tt.jt2.getText();
if(sl.length()==0){
javax.swing.JOptionPane.showMessageDialog(tt, "端口值不能为空");
System.exit(0);
}
int s2=Integer.parseInt(sl);
try {
//创建服务器
java.net.ServerSocket ss=new java.net.ServerSocket(s2);
s=ss.accept();
String sss="你好、、、、";
writeMsg(s,sss);
//这个线程用来启动输入流
readThread tc=new readThread(s,tt);
tc.start();
} catch (Exception ef) {
ef.printStackTrace();
}
}
//把我写好的信息发出去
else if("发送".equals(e.getActionCommand())){
String s3=tt.ja2.getText();
s3+="\r\n";
writeMsg(s,s3);
tt.ja2.setText("");//每次发送完毕后都将输入界面清空
}
//退出程序
else if("关闭".equals(e.getActionCommand())){
try {
s.close();
System.exit(0);
} catch (Exception e1) {
e1.printStackTrace();
System.exit(0);
}
}
3、上次的版本有一个Bug,就是点击创建按钮时会等客户端来接收这个Socket对象,如果没有接收的话就会卡死在那,然后我们用了一个线程来把接收Socket放到了这个线程中启动就会很好的改善这个问题。
public void run(){
while(true){
try {
Socket client=server.accept();
readThread rt=new readThread(client,tt);
rt.start();
lis.alist.add(rt);
sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
}
}
并且在这个线程中启动输入流线程。
4、接下来遇到的是只能每次与一个客户机进行聊天,要想实现多个客户端连接就要在同一个服务器上的话就要用到线程了。在启动输入流线程的时候服务器接收到的每个Socket对象就是不同的客户端,
public void run(){
while(true){
try {
Socket client=server.accept();
readThread rt=new readThread(client,tt);
rt.start();
lis.alist.add(rt);
sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
}
}
5.写客户机跟服务器差不多,界面基本一样,也是在得到登陆时现在获取IP地址和端口后实例化socket对象,并且启动一个输入流线程,然后在这里把用户的名字写过去,然后在服务器那边把读取线程改下,循环外面先读一次,也就是对应的用户名。然后在关闭按钮时出了一个问题,也就是你在点了关闭按钮时输入流关闭了,但是线程还在运行,线程中的socket对象此时已为空了,这就要求在输入流中加一个判断,判断socket对象是否为空。
public void run() {
try {
ins = s.getInputStream();
BufferedReader buffReader = new BufferedReader(new InputStreamReader(ins));
while (true) {
if (!s.isClosed()) {
String st = buffReader.readLine();
if (st == null)
return;
String sy = tt.ja1.getText();
st = sy + st + "\r\n";// 获取以前的聊天记录,并把新的记录加上去
tt.ja1.setText(st);// 显示
} else
return;
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
6.其实中间还改过不少版本,因为我用的都是构造器传参,这样程序的耦合性比较差,改动一个地方会有很大问题,要改好多地方才能实现这个功能。我知道这里应该用接口,而且最好把方法封装到一个类中,但是确实还不是怎么会,所以目前没搞出来。
最后的版本中用到了协议,1表示发送文字,2表示发送图片等文件。协议内容就是一开始写入的是整个文件长度,接下来是标示符 cmd 1或2, 1表示文字,2表示图片。在这里判断后就进入不同的写入方法,写入文字时要求读取的时候用的是BufferedReadLine 这个方法是根据根据后面的换行符判断是否为一句话,这样就可以在每句话发送时在后面加上一个/r/n,这样读取的时候就可以一句一句读了。
读取文件时,先弹出一个文件选择框,选择得到文件名,然后用文件读入流FileInputStream fis,把这个读到文件体长度的byte数组中。这个写完标识符后要写文件名字的长度,文件名,消息体内容。这就是一个简单的完整协议了。
// 把我写好的信息发出去
else if ("发送文字".equals(e.getActionCommand())) {
if (tt.ja2.getText() != null) {
String s13 = "服务器说 :" + tt.ja2.getText() + "\r\n";
String sy = tt.ja1.getText();
String s14 = sy + s13;
tt.ja1.setText(s14);
try {
for (int i = 0; i < alist.size(); i++) {
System.out.println("--dd"+alist.size());
alist.get(i).dos.writeInt(4+4+s13.length());
alist.get(i).dos.writeInt(1);
alist.get(i).sendMsg(s13);
}
} catch (Exception e1) {
e1.printStackTrace();
}
tt.ja2.setText("");// 每次发送完毕后都将输入界面清空
} else {
System.out.println("发送值不能为空");
}
}else
//判断发送的为文件,文件协议为先是一个int型的文件总长度,接下来是控制符 2代表图片,在就是名字长度,名字,文件体长度
if("发送图片".equals(e.getActionCommand())){
JFileChooser jfs=new JFileChooser();
jfs.setFileSelectionMode(JFileChooser.FILES_ONLY);
jfs.showOpenDialog(null);
File file=jfs.getSelectedFile();
String fileName=file.getAbsolutePath();
java.io.FileInputStream fis;
byte[] fileByte=null;
try {
fis=new java.io.FileInputStream(fileName);
int fileLen=(int)file.length();
totallenth=4+4+4+fileName.getBytes().length+fileLen;
fileByte=new byte[fileLen];
fis.read(fileByte);
} catch (Exception e1) {
e1.printStackTrace();
}
try {
for (int i = 0; i < alist.size(); i++) {
alist.get(i).dos.writeInt(totallenth);
alist.get(i).dos.writeInt(2);
alist.get(i).dos.writeInt(fileName.getBytes().length);
alist.get(i).sendMsg(fileName);
alist.get(i).dos.write(fileByte);
}
}catch(Exception ef){
ef.printStackTrace();
}
try {
Document doc = tt.ja1.getDocument();
ByteArrayInputStream bis = new ByteArrayInputStream(fileByte);
BufferedImage image = ImageIO.read(bis);
ImageIcon icon = new ImageIcon(image);
tt.ja1.setCaretPosition(doc.getLength());
tt.ja1.insertIcon(icon);
} catch (Exception ed) {
ed.printStackTrace();
}
}
然后客户机跟服务器的读入读出流都要严格根据协议走,哪一个地方不行都会出错。
通信其实代码不难,但是要统一协议,加上传参就比较麻烦了,而且出一点错都不行。
这时候就更体会得到代码的规范性的重要性,如果能用到接口和方法的封装性就会好很多。
分享到:
相关推荐
【标题】"基于UDP通信协议的网络聊天室"是一个实现多用户实时交流的软件项目,它利用了UDP(User Datagram Protocol)作为传输层协议。UDP是一种无连接的、不可靠的传输协议,它以较小的开销提供了快速的数据传输,...
【标题】:“简单聊天室简单聊天室简单聊天室C#” 【描述】:“一个简单的聊天室,基于webservice,采用C#编程语言实现。” 【标签】:“简单聊天室”、“简单”、“聊天室”、“聊天”、“C#” 在这个项目中,...
在本项目中,"简单的聊天室C#(asp.net)"是一个使用C#语言和ASP.NET框架构建的网络应用程序,旨在实现一个基本的在线聊天功能。这个项目包含了多个小实验和一个综合实验,覆盖了从基础到进阶的ASP.NET开发技术。...
7. **WebSocket**:为了提供实时通信,J2EE聊天室可能会使用WebSocket协议,它允许双向通信,使客户端和服务器能即时交换数据,提高用户体验。 8. **安全性**:J2EE提供了安全机制,如JAAS(Java Authentication ...
总之,“基于C语言的简易聊天室”项目不仅涵盖了网络通信的基本原理,还涉及到了多线程、数据格式化和错误处理等多个方面,对于学习和提升C语言编程及网络编程技能非常有益。通过这个项目,开发者能够更深入地理解...
【简易聊天室_聊天室_】是一个实现两台主机间通信的应用程序,它允许用户通过互联网进行实时对话。这个项目的核心在于构建一个简单的聊天环境,让用户能够交换各种类型的数据,包括数字、字符、汉字和英文字母。在IT...
这是一份专为初学者设计的简易聊天室项目,旨在帮助他们理解和掌握聊天室的基本构建与运作原理。在IT行业中,聊天室是一种常见的实时通讯应用,它允许用户之间进行实时的文字、语音或者视频交流。通过这个项目,你将...
在IT行业中,构建一个多人聊天室是常见的应用场景,如标题所示,这通常涉及到网络通信、多线程编程、用户界面设计等技术。这篇博客“通信——实现多人聊天室”(博文链接:...
Java基于UDP传输协议的简单聊天室是一个典型的网络编程示例,它涵盖了多个核心知识点,包括Java的Socket编程、用户数据报协议(UDP)以及JSON数据格式的使用。在这个项目中,我们将深入理解这些概念并探讨如何将它们...
C++多人聊天室的构建 本文介绍了基于CAsyncSocket类的Windows Sockets编程的基本方法,并通过一个应用实例,编写服务端和客户端代码,...这种方法可以方便地实现多人聊天室的构建,并提供了灵活和可靠的网络通信机制。
【标题】"简易聊天室 很简单的"所涉及的知识点主要集中在构建一个基本的在线聊天室系统上。这个系统可能是为了实现用户之间的实时交流,它可能包含以下关键组成部分和技术: 1. **网络通信协议**:简易聊天室的核心...
【标题】:“C++开发的简易聊天室的源代码文件”揭示了使用C++编程语言构建的一个基础级网络通信应用,即一个简单的聊天室。在这个项目中,开发者旨在实现两个核心功能:远程控制电脑的开关机以及双向通信。C++是一...
【简单聊天室】是一个基础的网络通信应用,它实现了客户端与服务端的实时通信功能,让用户可以进行多人在线聊天。这个项目主要运用了TCP/IP协议,确保数据在互联网中的可靠传输。下面将详细阐述该聊天室的核心知识点...
在本项目"简易聊天室.zip"中,开发者利用JAVA GUI(图形用户界面)和TCP(传输控制协议)网络编程技术,构建了一个具有登陆注册功能的简单聊天应用。这个项目主要涵盖了以下几个关键知识点: 1. **JAVA GUI**:GUI...
【ASP简单聊天室】是一种基于ASP(Active Server Pages)技术构建的在线交流平台,它为用户提供了一个基础但功能丰富的聊天环境。在这个聊天室中,用户可以进行公聊,即所有在线用户都能看到的信息交流,同时还有...
在构建一个简单的聊天室时,TCP是常用的选择,因为它能保证数据的有序性和完整性。下面将详细阐述如何使用TCP协议创建一个简单的聊天室,并涉及多线程在其中的应用。 首先,我们要理解TCP的基本工作原理。TCP通过三...
综上所述,构建一个基于Web的简易聊天室是一个涉及多方面技术的综合性项目,需要开发者具备扎实的Web基础知识,以及对实时通信和音视频处理的深入理解。通过这个项目,开发者可以提升自己的全栈开发能力,并在实践中...
【标题】"简单的聊天室"涉及的是创建一个基础的在线交流平台,通常称为聊天室,让用户可以实时发送和接收消息。这种系统的核心是实现客户端(Client)与服务器端(Server)之间的通信,允许用户通过网络进行互动。在...
这里我们将深入探讨UDP协议的特点以及如何利用其特性构建聊天室程序。 首先,UDP协议的主要特点是轻量级和高效。由于它不进行连接建立和维护,没有复杂的流量控制和错误校验机制,因此通信开销小,适合于实时性要求...
【简易聊天室(asp.net实现)】 在信息技术领域,构建一个在线聊天室是常见的实践项目,它可以帮助开发者熟练掌握Web应用程序的设计与实现。本项目基于ASP.NET和C#语言,旨在提供一个简单、实用的实时通信平台。ASP...