java socket多线程聊天室_Java学习之结合多线程技术,实现客户端和服务端任意通讯的“聊天室”功能...

1.、首先,是基于TCP的Socket的单次通信,简单的发送一次消息,得到一次消息

代码如下:

客户端

package com.chenpeng.client;

import java.io.BufferedReader;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.Socket;

import java.util.ArrayList;

import java.util.List;

public class Client {

public static void main(String[] args) throws IOException {

//(1)创建Socket对象

Socket client=new Socket("localhost",9999);

//(2)从键盘获取数据

BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

//(3)获取输出流

DataOutputStream dos=new DataOutputStream(client.getOutputStream());

//(4)获取输入流

DataInputStream dis=new DataInputStream(client.getInputStream());

String str=br.readLine();

dos.writeUTF(str);//向服务器端发送数据

System.out.println(dis.readUTF());//接收服务器端的数据

}

}

服务器端:

package com.chenpeng.server;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.IOException;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.ArrayList;

import java.util.List;

public class Server {

public static void main(String[] args) throws IOException {

System.out.println("----------------服务器端已开启---------------------");

//(1)创建ServerSocket对象

ServerSocket server=new ServerSocket(9999);

//(2)监听客户端是否有客户端请求连接

Socket socket=server.accept();

//获取输入流

DataInputStream dis=new DataInputStream(socket.getInputStream());

//获取输出流

DataOutputStream dos=new DataOutputStream(socket.getOutputStream());

String str=dis.readUTF();

System.out.println("客户端发送了:"+str);

dos.writeUTF("服务器端收到了:"+str);

//(5)关闭流

CloseUtil.closeAll(dos,dis,socket);

}

}

工具类:省略,主要是关闭流和socket

缺点:

只能实现客户端发一次消息,服务器端发一次信息

如果我们要实现像QQ一样聊天那样,可以一直发,一直回复怎么办呢?

答:使用循环就可以一直发,使用多线程,发送消息和接收消息使用线程来就可以解决不用先发之后,再等服务器端的回复,而是发送和回复都可以同时进行。

接收数据的方法:

package com.chenpeng.util;

import java.io.DataInputStream;

import java.io.IOException;

import java.net.Socket;

/**

* 接收数据的线程

* @author chenpeng

*

*/

public class Receive implements Runnable {

//用于接收数据的数据流

private DataInputStream dis;

private boolean flag= true;

//构造方法

public Receive(Socket client) {

try {

dis = new DataInputStream(client.getInputStream());

} catch (IOException e) {

//有异常,则关闭资源

flag = false;

CloseUtil.closeAll(dis,client);

}

}

//接收数据的方法

private String getMessage() {

String str ="";

try {

str = dis.readUTF();

} catch (IOException e) {

flag = false;

CloseUtil.closeAll(dis);

}

return str;

}

@Override

public void run() {

while(flag) {

System.out.println(this.getMessage());

}

}

}

发送数据的方法:

package com.chenpeng.util;

import java.io.BufferedReader;

import java.io.DataOutputStream;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.Socket;

/**

* 发送消息的线程

* @author chenpeng

*

*/

public class Send implements Runnable{

//从键盘获取数据

private BufferedReader br;

//发送数据使用数据输出流

private DataOutputStream dos;

private boolean flag = true;//默认为true

//无参构造方法

public Send() {

br = new BufferedReader(new InputStreamReader(System.in));

}

//有参构造器

public Send(Socket client) {

this();//调用本类的无参构造方法

try {

dos = new DataOutputStream(client.getOutputStream());

} catch (IOException e) {//有问题则关闭

flag= false;

CloseUtil.closeAll(dos,client);

}

}

//从键盘得到信息

private String getMessage() {

String str="";

try {

str =br.readLine();

} catch (IOException e) {

flag = false;//

CloseUtil.closeAll(br);

}

return str;

}

//发送给服务端

private void send(String str) {

try {

dos.writeUTF(str);

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

try {

dos.flush();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

@Override

public void run() {

while(flag) {

//调用发送信息的方法

this.send(getMessage());

}

}

}

服务端方法:

/**

* 服务端

*

* @author chenpeng

*

*/

public class Server {

public static void main(String[] args) throws IOException {

System.out.println("----------服务端-----------");

// 1.创建一个ServerSocket对象

ServerSocket server = new ServerSocket(8848);

// 2.监听客户端是否发请求过来

Socket client = server.accept();

// 创建接收数据的线程

Receive receive = new Receive(client);

// 创建发送数据回去的线程

Send send = new Send(client);

//启动线程

new Thread(receive).start();

new Thread(send).start();

}

}

客户端的方法:

package com.chenpeng.Thread;

import java.io.IOException;

import java.net.Socket;

import java.net.UnknownHostException;

/**

* 客户端

* @author chenpeng

*

*/

public class Client {

public static void main(String[] args) throws UnknownHostException, IOException {

System.out.println("--------客户端---------");

//创建Socket对象

Socket client= new Socket("localhost",8848);

//创建发送的线程类对象

Send send = new Send(client);

//创建接收的线程类对象

Receive receive = new Receive(client);

//创建Thread类对象的线程并启动线程

new Thread(send).start();

new Thread(receive).start();

}

}

这时候就可以实现客服端发消息,服务器端也能发消息,简单实现了QQ的聊天功能,原理就是两边都使用发送数据和接收数据的线程,然后一直循环。

但是有个小问题,如果我再启动一个客户端发送消息,是不会到服务端的?这里等我思考之后什么回事再解决吧,今天主要是实现“群聊”的功能

3、现在,到了实现“群聊”的时候了

思路:

1、首先基本上和上面客户端和服务器端一直聊没区别,也是使用了发送消息的线程和接收消息的线程

2、但是这里问题来了,一个客户端发送消息,如何让其他的客户端接收到消息呢?这时候,我们需要在服务器端来一个线程类MyChannel,用来记录每个客户端发送的数据,然后再使用群发的功能sendOther(),不能发给自己,所以我们在服务器端上面创建了一个Arraylist集合,用于存放运行着的线程。

package com.chenpeng.util;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.IOException;

import java.net.Socket;

import java.util.List;

/**

* 每一个客户端都是一条道路

* 1.输入流

* 2.输出流

* 3.接收数据

* 4.发送数据

* @author chenpeng

*

*/

public class MyChannel implements Runnable {

private DataInputStream dis;

private DataOutputStream dos;

private boolean flag = true;

//构造方法

public MyChannel(Socket client) {

try {

dis = new DataInputStream(client.getInputStream());

dos = new DataOutputStream(client.getOutputStream());

} catch (IOException e) {

flag = false;

CloseUtil.closeAll(dis,dos);

}

}

//接收数据的方法

private String receive() {

String str ="";

try {

str = dis.readUTF();

} catch (IOException e) {

flag = false;

CloseUtil.closeAll(dis,dos);

Server.list.remove(this);

}

return str;

}

//发送数据的方法

private void send(String str) {

if(str!=null&&str.length()!=0) {

try {

dos.writeUTF(str);

dos.flush();

} catch (IOException e) {

flag= false;

CloseUtil.closeAll(dos,dis);

Server.list.remove(this);

}

}

}

//转发的方法

private void sendOther() {

String str = this.receive();

List list = Server.list;

for(MyChannel other: list) {

if(other == this) {

continue;//不发给自己

}

other.send(str);//发送数组

}

}

@Override

public void run() {

while(flag) {

//调用发送数据的方法

sendOther();

}

}

}

注意:客户端这里使用了while循环,一直监听者客户端有没有客户端连接

总结:

单次聊天只能先发数据,然后才能接收数据,如果不发就收不到,因为接收和收到是在一个线程里面实现的,不符合实际的情况

解决方案:

1、想要多次聊天可以使用循环

2、先发后收的的问题可以使用线程来解决,一个接收数据的线程,一个发送数据的线程

已标记关键词 清除标记
一个关于嵌入式系统很详细的文档 第1章 概 述 1.1 研发背景 随着电子技术的发展,微型计算机应用迅速渗透到各个领域。工业控制领域中计算机应用从编程器、单板机、微机系统到工业网络,由简单到复杂,对软件的要求越来越高。近年来网络技术的飞速发展,又为工业自动化开辟了广阔的发展空间,用户可以方便快捷地组建优质高效的监控系统,并且通过采用远程监控及诊断、双机热备等先进技术,使系统更加安全可靠,在这方面,出现了许多应用软件,其中的典型代表就是工控组态软件,如昆仑通态软件公司的MCGS,亚控公司的组态王,Intellution公司的!FIX等。 组态软件的目的就是提供给用户一种二次开发平台,尽量减少组建工程过程中的重复劳动,隐蔽复杂的编程过程。而目前的组态软件大多停留在对人机界面的组态上,随着我国工业自动化水平的不断提高和普及,对工控组态软件的要求也越来越高。对设备驱动程序的可组态是目前研究的热点。 一直以来,工业控制软件缺乏统一的工业标准,不同厂家的软件之间进行通讯是非常麻烦的一件事。各个厂家的软件对控制系统硬件操作的设备驱动程序接口也各不相同,这样为了对市场上不同厂家的设备都能管理,控制软件厂家必须针对市场上的几百种常用的设备都开发设备驱动程序,而且当硬件设备升级、修改时,驱动程序也必须修改,这样做的代价无疑是相当高的。目前并没有一种软件能够很好的实现对设备驱动的所见即所得的支持[1]。出现这种现象的原因主要是外部设备种类繁多,所基于的协议也是千差万别,如果要实现一种比较通用的驱动很不容易。但是我们可以考虑提供一个一般工程人员非常熟悉的开发环境,在这个环境中通过简单易行的操作实现数据的采集和控制。用户只需要关注他们熟知的通讯规程,然后用一种图形化的方法来实现通讯的一个过程,而不需要对程序内部实现有所了解。所以希望通过这种二次开发平台的设计、开发来解决工控软件与大部分的硬件设备数据交换问题。 1.2 本文的目的和意义 本文主要目的是研究面向对象软件开发技术和软件设计模式在工业数据采集软件设计开发中的应用。内容基于一套包含多种智能控制模块的嵌入式实时控制软件,实际上就是一套软PLC软件包,并结合当前工控组态软件实际情况,开发符合国际标准的功能块图(Function Block Diagram?FBD)编程语言[3],即第四代编程语言(4GL语言),以方便用户的组态为目的,使用户不需要编程经验就可组态出优质高效的符合自己需求的工业控制系统,其功能块编译后实际上生成第三代编程语言(3GL语言),而本文要实现的FBD也就是C++的代码生成器。 这种FBD编程语言有着很广泛的应用价值: 首先,普通的工控组态软件要与设备连接,必须有支持所挂设备的驱动程序,运用符合标准的图形化FBD编程模块后,将不需对市场上的几百种常用的设备都开发设备驱动程序,也不需要专门的编程人员,而由用户根据实际需要,应用功能块来搭建完成,打破了组态软件仅限于人机界面的组态局面,实现设备驱动的可组态。例如可移植到北京昆仑通态自动化软件科技有限公司最新推出的嵌入式组态软件??MCGSE中,使其可以用图形化的FBD语言组态设备和策略,将监控和软逻辑集成一体。 其次,运用于嵌入式实时控制软件,可以作为独立的开发环境,与工控机配合使用,形成软PLC。形成一套面向中小型过程应用和设备集成控制的开放型控制系统。满足工控行业从简单到复杂的各种控制应用要求和各种设备过程自动化控制的应用要求,是用来代替硬PLC(可编程控制器)[4] 和各种设备过程控制系统的理想解决方案。 社会的发展以及先进的生产管理理念的不断引入,当今用户不仅要求系统本身能够完成各种常规及先进的控制要求,而且要求通过友好的动画界面显示现场生产的状况。普通的PLC加HMI人机接口界面软件构成的系统在快速逻辑控制应用领域有其优势[1],尤其在断续的生产过程以及各种设备控制应用领域有他的市场并能保持较为适中的系统价格,但在连续复杂的过程控制以及各种针对特殊应用要求的领域和具备先进的生产管理方面满足不了用户的要求,同时系统的可靠性也有待提高。我们通过软PLC来代替普通的PLC,并集成到现有的MCGS人机界面组态软件中不失为解决上述问题的好方法,实现将图形组态与控制器组态相结合。 笔者主要负责其中基于功能流程图的驱动程序软件的设计和开发,以实现设备驱动的可组态,使用户可方便的用FBD来开发设备驱动,针对大多数的工业过程控制应用如:石油化工、电站、钢铁冶炼、食品加工等要求,完成对控制器的控制策略的组态。工程人员只需简单地从功能块库中拖拽所需功能块到组态窗口中并用软接线连接起来就可快速的生成需要的控制策略。使用规范的FBD编程语言来增强昆仑通态的组态软件??MCGS的脚本处理功能和策略功能,提供可视化的I/O设置
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
<p> <span style="color:#3D3D3D;"></span> </p> <span style="font-size:18px;">     本课程为JavaSE基础阶段的项目实战视频,主要使用技术均为JavaSE基础,手把手带你构建在线聊天室,需要JavaSE基础才能进行实战与开发,学习前需要掌握的技能有:逻辑基础、面向对象、异常处理、集合框架、IO流、网络编程、多线程、GUI技术,学完本套课程,你会对JavaSE有一个更深入的认知,为后续课程的学习打下一个坚实的基础。<br /> </span> <p> <br /> </p> <p> <br /> </p> <p> <span style="color:#3D3D3D;"><strong>课程大纲</strong></span> </p> <span style="color:#3D3D3D;"> </span> <div style="text-align:left;"> <span style="font-size:18px;">1. </span><span style="color:#222222;">网络聊天室认知及原理</span><span style="font-size:18px;">;</span> </div> <span style="color:#3D3D3D;"> </span> <div style="text-align:left;"> <span style="font-size:18px;">2. 登录、</span><span style="color:#222222;">聊天室服务端界面制作</span><span style="font-size:18px;">;</span> </div> <span style="color:#3D3D3D;"> </span> <div style="text-align:left;"> <span style="font-size:18px;">3. 客户端/服务端</span><span style="color:#222222;">网络通信实现</span><span style="font-size:18px;">;</span> </div> <span style="color:#3D3D3D;"> </span> <div style="text-align:left;"> 4. 通信机制设计; </div> <span style="color:#3D3D3D;"> </span> <div style="text-align:left;"> 5. 在线统计、消息收发主功能实现; </div> <span style="color:#3D3D3D;"> </span> <div style="text-align:left;"> <span style="font-size:18px;">6. 服务端功能实现;</span> </div> <span style="color:#3D3D3D;"> </span> <div style="text-align:left;"> 7. 字体及图片样式发送; </div>
小明用基于socket通道做了一个实时聊天,实现了多客户客户端服务端的实时通信,但是老师要求每个人都有自己的独特功能........于是,小明想,创新是不可能创新的,那现在QQ的工鞥有什么能够移植的呢,,,小明效果了一圈,发现大多功能都是基于文件传输,去找了一下socket的文件传输,果断撂挑子。还有什呢,要不就自己客户端约定好,特殊的字符串表示特殊操作,比如下面小明要举个例子:                                                                                                                                   有两个客户端A、B,客户端都是一模一样的,里面资源实现存放好10张图片,并且约定:发送消息为“@”的时候,这个字符串后边会跟着一个数字,咱们两个同时把数字代表编号的图片输出到聊天框,如                                                                A发送给B:@     那现在,两个客户端就会把3号图片输出到聊天框,造成发送的是图片的假象 说干就干,先实现自己窗口判断输出图片,在获取于是先在获取聊天输入区文本时做判断(我正添加表情按钮,到时候就不用记住暗号了),在输出相应编号图片,欸不对啊,这个聊天信息展示区是个文本框啊,那就给改成面板,使用新建面板类,使用流式布局规定布局宽度(不然他会横着输出消息)然后是面板添加滚动条,然后再聊天区打出来就好了 ----(一个积分,望土豪点一点,我也想恰饭) 你们看到这个代码的时候,我主页应该就有相关博文了,大家可以去参考
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页