竹笋

注册

 

发新话题 回复该主题

AndroidSocket实现简易聊 [复制链接]

1#

人的一生总要去书写许多不知结局的故事。有的故事可以顺利完成,而有的故事或许将永远都是一种残缺。完美的结局是我们搏击风雨的见证,也是我们永久的期待,然而生活并不像我们所想象的那样美好,既然有年轻,也必然有衰老。

简易聊天室,什么是聊天室呢,简单一点说就是一些人可以共同聊天,别人能够看见你发布的消息,你也可以看到别人的消息,大家的消息是公开的。

功能分析:

1、聊天功能,聊天是一个长时间的相互交互的过程,要实现长时间连接Socket是一个比较不错的选择。

2、一些人相互聊天功能,要想实现相互聊天,就要将消息转发给所有建立连接的人,这里就要进行消息转发。

实现思路:

利用Socket实现客户端和服务端长连接,每次将连接进来的Socket保存到一个集合当中,当其中一个Socket有接收到数据的时候,将接收到的数据转发给其他的Socket,这样既能实现聊天功能又能实现转发。

对Socket的操作应放在子线程当中,每一次有新的Socket连接进来之后就新开一个子线程。

如果对Socket不是很了解,推荐Socket简单体验,TCP和UDP这篇文章进行了解。

服务端搭建

首先要实现监听客户端连接,需要利用ServerSocket的accept方法进行监听,但是该方法会将程序阻塞,所以该监听过程要放在子线程中完成。这里定义的线程为ServerListener。

其次每监听到一个Socket,Socket无论是获取还是传输过程都是对字节流进行操作,这是一个比较耗时的操作,所以也要放在子线程中操作。这里定义的线程为ChatSocket。

最后还要定义一个Socket的子线程管理类,方便对所有连接进来的Socket的子线程进行管理,例如对数据的转发。这里定义的管理类为ChatManager。

在程序最开始运行的时候,要开启对Socket连接的监听,所以在main方法中开始监听线程。

publicstaticvoidmain(String[]args){//开启服务端监听newServerListener().start();}

开启监听线程之后,当监听到有Socket进行连接的时候,不仅要新建一个子线程实现该Socket的操作,而且要把该Socket添加到Socket线程管理类ChatManager当中,方便后期管理。

publicclassServerListenerextendsThread{

Overridepublicvoidrun(){try{//1、创建ServerScoket,设置端口ServerSocketserverSocket=newServerSocket();while(true){//2、accept方法将导致程序阻塞Socketsocket=serverSocket.accept();JOptionPane.showMessageDialog(null,有客户端连接到本机的端口);//3、将socket传递给新线程ChatSocketcs=newChatSocket(socket);cs.start();//4、使用Chatmanager进行管理ChatManager.getInstance().add(cs);}}catch(IOExceptione){e.printStackTrace();}}}

在ChatSocket新线程中,要实现对接收到的Socket进行处理,例如获取Socket客户端发送过来的数据进行转发等。而转发过程,是转发给所有连接进来的Socket,所以转发过程的实现将由ChatManager完成。

ChatSocket在一开启线程的时候,就要进行客户端数据获取,并转发。

ChatSocket要能够完成服务端想客户端发送数据的过程。

publicclassChatSocketextendsThread{privateSocketsocket;publicChatSocket(Socketsocket){this.socket=socket;}//服务端传值给客户端publicvoidout(Stringout){try{if(socket.isConnected()!socket.isClosed()){//获取当前Socket输出流,输出数据socket.getOutputStream().write(out.getBytes(gbk));System.out.println(转发数据**********+out);}else{//链接已关闭ChatManager.getInstance().remove(this);}}catch(IOExceptione){e.printStackTrace();}}

Overridepublicvoidrun(){try{if(socket.isConnected()!socket.isClosed()){//接受客户端数据BufferedReaderbr=newBufferedReader(newInputStreamReader(socket.getInputStream(),gbk));//读取数据Stringline=null;while((line=br.readLine())!=null){//转发数据ChatManager.getInstance().publish(this,line);System.out.println(接受数据******+line);}br.close();}else{//链接已关闭ChatManager.getInstance().remove(this);}}catch(UnsupportedEncodingExceptione){e.printStackTrace();}catch(IOExceptione){e.printStackTrace();}}}

最后来说说Socket线程管理类ChatManager,一个聊天室只能有一个Socket线程管理类,所以该类要使用单例模式。

privatestaticChatManagercm;//单例publicstaticChatManagergetInstance(){if(cm==null){cm=newChatManager();}returncm;}

提供Socket子线程存放集合,能够实现Socket子线程添加和移除功能。

//ChatSocket集合Vectorvector=newVector();//添加ChatSocketpublicvoidadd(ChatSocketchatSocket){vector.add(chatSocket);}//移除ChatSocketpublicvoidremove(ChatSocketchatSocket){vector.remove(chatSocket);}

最后是借助Socket子线程存放集合,实现数据转发功能。

//发送消息publicvoidpublish(ChatSocketcs,Stringout){for(inti=0;i

Android端搭建

对于Android客户端而言就显得稍微简单一些,只需要实现数据的接受和传递即可。

首先是界面的构建:

客户端界面当点击连接的时候,客户端会向服务端发送连接请求,请求成功之后便可发送消息,聊天内容将会在界面中间部分显示。

1、初始化信息,在Activity中完成对控件的初始化和点击事件监听。

//定义控件全局变量privateTextViewipTv,contentTv;privateButtonlinkBtn,sendBtn;privateEditTextsendEd;//初始化控件privatevoidinitView(){ipTv=(TextView)findViewById(R.id.tv_ip);contentTv=(TextView)findViewById(R.id.tv_content);linkBtn=(Button)findViewById(R.id.btn_link);linkBtn.setOnClickListener(this);sendBtn=(Button)findViewById(R.id.btn_send);sendBtn.setOnClickListener(this);sendEd=(EditText)findViewById(R.id.ed_send);}//点击事件监听

OverridepublicvoidonClick(Viewv){switch(v.getId()){caseR.id.btn_link://链接connect();break;caseR.id.btn_send://发送send();break;}}

2、连接服务端,并获取服务端传递数据。

//定义三个全局变量privateSocketsocket;privateBufferedReaderreader;privateBufferedWriterwriter;//连接Socket服务端privatevoidconnect(){finalStringip=ipTv.getText().toString().trim();finalintport=;//异步执行AsyncTaskasyncTask=newAsyncTask(){

OverrideprotectedVoiddoInBackground(Void...params){try{//实例化Socketsocket=newSocket(ip,port);reader=newBufferedReader(newInputStreamReader(socket.getInputStream()));writer=newBufferedWriter(newOutputStreamWriter(socket.getOutputStream()));publishProgress(success);//读取传递过来的数据Stringline;while((line=reader.readLine())!=null){publishProgress(line);}}catch(IOExceptione){publishProgress(failed);e.printStackTrace();}returnnull;}

OverrideprotectedvoidonProgressUpdate(String...values){if(success.equals(values[0]))Toast.makeText(MainActivity.this,连接成功,Toast.LENGTH_LONG).show();elseif(failed.equals(values[0]))Toast.makeText(MainActivity.this,无法建立连接,Toast.LENGTH_LONG).show();elsecontentTv.append(他说:+values[0]+\n);super.onProgressUpdate(values);}};asyncTask.execute();}

注意连接服务端和都去服务端数据是一个耗时的操作,所以应放在子线程中完成,这里是采用异步AsyncTask的方式来进行处理。

3、发送数据

//向Socket服务端发送privatevoidsend(){Stringout=sendEd.getText().toString().trim();//发送数据try{writer.write(out+\n);writer.flush();sendEd.setText();contentTv.append(我说:+out+\n);}catch(IOExceptione){e.printStackTrace();}}

到这里就已经全部完成了,包括服务端和Android客户端的实现,在实际开发当中往往是通过构建一些比较成熟的框架来实现这一过程,实现原理大致相同,实现过程有所不同。

Github后台代码地址[

分享 转发
TOP
发新话题 回复该主题