Android Socket通信实现简单聊天室

socket通信是基于底层TCP/IP协议实现的。这种服务端不需要任何的配置文件和tomcat就可以完成服务端的发布,使用纯java代码实现通信。socket是对TCP/IP的封装调用,本身并不是一种协议,我们通过socket来调用协议来跟服务端进行通信和数据的传输。socket就像客户端与服务端之间的一条信息通道,每一个不同的客户端都会建立一个独立的socket,双方都没有关闭连接的话,连接—也就是建立好的这条socket通道将一直保持,服务端要跟那一个客户端通信只需要找到对应的socket对象就可以进行数据传递。

第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

一. 服务端:在客户端跟服务端通信之前,服务端必须先开启。首先来看一下服务端Socket的编写吧。服务端就是一个简单的java项目,由于聊天室可能会有多个客户端同时连接并发送消息,我们这里使用线程池来处理客户端的请求。

List<Socket> list = new ArrayList<Socket>();
ExecutorService executorService;
 BufferedReader br;
 private static final int PORT = 12345;
 private static final int POOL_SIZE = 5 ;

public Socket_Server() throws IOException {
  executorService = Executors.newFixedThreadPool(POOL_SIZE);
  ServerSocket serverSocket = new ServerSocket(PORT);
  System.out.println(serverSocket.getInetAddress().getHostAddress() + ":服务端就绪。");
  Socket client = null;
  while (true) {//为每一个连接到服务器的客户端分配一个线程进行消息的接收和发送
   client = serverSocket.accept();
   list.add(client);
   executorService.execute(new Service(client));
  }
 }

首先我们创建了一个大小为5的固定大小线程池,并创建端口号为12345的服务端socket接收客户端请求,通过一个while循环不断轮询来自服务端的连接请求,在while循环里面调用了serverSocket.accept();是线程进入阻塞状态,也就是说在没有接收到客户端的请求时,程序将一直停留在这里,当有客户端连接服务端是,代码开始往下走,我们把接收到的客户端socket放入list里面,这样我们就把所有连接到服务端的socket保存下来了,这样就使得我们可以随时对任一客户端进行数据传递。之后就是线程池调用execute执行一个线程,把连接过来的socket作为参数传进去。接下来分析下service的内容:

class Service implements Runnable {

  Socket client;
  BufferedReader br;
  String msg = "";

  public Service(Socket client) {
   this.client = client;
   try {
    br = new BufferedReader(new InputStreamReader(
      client.getInputStream()));
    msg = "用户:" + client.getInetAddress() + "加入了聊天室,当前人数:"
      + list.size();
    sendMsg();
   } catch (Exception e) {
    e.printStackTrace();
   }

  }

  public void run() {
   try {
    while (true) {

     if ((msg = br.readLine()) != null) {
      if(msg.equals("bye")){
       list.remove(this.client) ;
       br.close() ;
       msg = "用户:" + client.getInetAddress() + "离开了聊天室,当前人数:" + list.size();
       sendMsg() ;
       client.close() ;
       break ;
      }else{
       msg = client.getInetAddress() + "说:" + msg;
       sendMsg() ;
      }
     }
    }
   } catch (Exception e) {
    e.printStackTrace();
   }
  }

  public void sendMsg() {//为每一个用户发送这个消息:msg
   PrintWriter pw;
   System.out.println(msg);
   for (Socket client : list) {
    try {
     pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
       client.getOutputStream())));
     pw.println(msg);
     pw.flush() ;
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  }
 }

在service的构造方法中使用了作为参数传进来的socket,在里面我们通过这个socket获取输入流包装成一个BufferedReader,br = new BufferedReader(new InputStreamReader(client.getInputStream()));这里我们是主要是针对聊天,所以使用的是字符流进行数据的传输,这个类里面声明了一个成员变量msg,通过这个变量来给每个客户端发送信息。下面看下sendMsg方法:

public void sendMsg() {//为每一个用户发送这个消息:msg
   PrintWriter pw;
   System.out.println(msg);
   for (Socket client : list) {
    try {
     pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
       client.getOutputStream())));
     pw.println(msg);
     pw.flush() ;
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  }

这里我们通过遍历list里面的每个socket获得它的的输出流并且包装成PrintWriter 向客户端发送信息, pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())));向每一个客户端发送成员变量msg内容,在PrintWriter调用print之后一定要调用flush刷新输出流进行数据的传递,否则客户端无法接收到服务端发送的数据。接下来看这个类的住方法 run:

public void run() {
 try {
  while (true) {

   if ((msg = br.readLine()) != null) {
    if(msg.equals("bye")){
     list.remove(this.client) ;
     br.close() ;
     msg = "用户:" + client.getInetAddress() + "离开了聊天室,当前人数:" + list.size();
     sendMsg() ;
      client.close() ;
       break ;
      }else{
     msg = client.getInetAddress() + "说:" + msg;
    sendMsg() ;
    }
     }
    }
   } catch (Exception e) {
    e.printStackTrace();
   }
  }

与前面类似,也是通过一个while进行无限循环进行读取socket的输入流,如果内容不为空就调用sendmsg对每一个客户端进行信息发送,有个小小的处理就是如果发送过来的信息是bye的时候就断开对应socket的链接,退出聊天室。以上是对服务端的分析,接下来我们来看Android客户端。

二. 客户端:客户端基本与服务端一样,我们直接上代码吧。

 //首先还是贴出成员变量

 private Button send;
 private EditText edt_input;
 private TextView txt_content;
 private static final String SERVER_PATH = "172.16.10.18";
 private static final int PORT = 12345;
 private Socket client;
 private BufferedReader br;
 private PrintWriter pw;
 private StringBuffer content = new StringBuffer();

 private void initView() {
  send = (Button) findViewById(R.id.send);
  edt_input = (EditText) findViewById(R.id.input);
  txt_content = (TextView) findViewById(R.id.chat_content);
  // --------发起网络连接-----
  new Thread() {
   public void run() {
    try {
     client = new Socket(SERVER_PATH, PORT);
     br = new BufferedReader(new InputStreamReader(
       client.getInputStream()));
     pw = new PrintWriter(new BufferedWriter(
       new OutputStreamWriter(client.getOutputStream())));
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  }.start();

  send.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    if (client != null && client.isConnected() && !client.isOutputShutdown()) {
     String input = edt_input.getText().toString();
     pw.println(input);
     pw.flush();
     ((EditText)findViewById(R.id.input)).setText("");
    }
   }
  });

  new Thread(this).start();
 }

首先还是传统的new一个thread来建立与服务端的连接,因为主线程不能访问网络,由于我们客户端肯定是只有当前这一个socket的,所以只有一个线程,不用跟服务端一样使用线程池了。连接一旦建立,获取socket的输入输出流来包装成对应的BufferedReader和PrintWriter:br = new BufferedReader(new InputStreamReader(client.getInputStream()));pw = new PrintWriter(new BufferedWriter( new OutputStreamWriter(client.getOutputStream())));由于这里只会使用一个socket,所以这里的相关变量都可以使用成员变量。然后走下来就是对send按钮的监听,点击发送的话,把内容发送给服务端,服务端接收到之后发送给每一个保持着链接的客户端。这个activity也是实现了runnable接口的,接下来看run方法:

public void run() {
  while (true) {
   if (client != null && client.isConnected()
     && !client.isInputShutdown()) {
    try {
     String response;
     if ((response = br.readLine()) != null) {
      content.append(response + "\n");
      mHandler.sendEmptyMessage(UPDATE_CONTENT);
     }
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  }
 }

这里跟服务端一样,通过一个while无限循环读取来自服务端的信息,一旦读取到信息之后就通过handler从子线程发送消息到主线程,主线程进行数据的更新,其实就是向显示聊天室内容的textview追加聊天内容并且setText上去:

Handler mHandler = new Handler() {
  public void handleMessage(Message msg) {
   switch (msg.what) {
   case UPDATE_CONTENT:
    txt_content.append(content);
    break;

   default:
    break;
   }
  };
 };

总体来说客户端还是比服务端容易点,没有涉及到并发,只需要做当前这个客户端对应的socket通信就行了。以上就是对socket的一个简单总结和在安卓里面的简单应用实现聊天室功能。效果图:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • Android使用Websocket实现聊天室
  • Android使用多线程进行网络聊天室通信
  • android socket聊天室功能实现
  • Android 基于Socket的聊天室实例
  • Android编写简单的聊天室应用
  • Android中基于XMPP协议实现IM聊天程序与多人聊天室
  • Android高仿微信聊天界面代码分享
  • Android蓝牙通信聊天实现发送和接受功能
  • android Socket实现简单聊天功能以及文件传输
  • Android仿微信语音聊天功能
(0)

相关推荐

  • android Socket实现简单聊天功能以及文件传输

    干程序是一件枯燥重复的事,每当感到内心浮躁的时候,我就会找小说来看.我从小就喜爱看武侠小说,一直有着武侠梦.从金庸,古龙,梁羽生系列到凤歌(昆仑),孙晓(英雄志)以及萧鼎的(诛仙)让我领略着不一样的江湖. 如果你有好看的武侠系列小说,给我留言哦.题外话就扯这么多了,接着还是上技术. 看看今天实现的功能效果图: 可以这里使用多台手机进行通讯,我采用的服务器发送消息. 是不是只有发送消息,有些显得太单调了.好,在发送消息的基础上增加文件传输.后期会增加视频,音频的传输,增加表情包.那一起来看看图文消

  • Android中基于XMPP协议实现IM聊天程序与多人聊天室

    简单的IM聊天程序 由于项目需要做一个基于XMPP协议的Android通讯软件.故开始研究XMPP. XMPP协议采用的是客户端-服务器架构,所有从一个客户端发到另一个客户端的消息和数据都必须经过XMPP服务器转发,而且支持服务器间DNS的路由,也就是说可以构建服务器集群,使不同的 服务器下的客户端也可以通信,XMPP的前身是一个开源组织制定的网络通信协议--Jabber,XMPP的核心是在网络上分片段发送XML流的协议,这个协议是XMPP的即时通讯指令的传递手段.       为了防止服务器间

  • Android蓝牙通信聊天实现发送和接受功能

    很不错的蓝牙通信demo实现发送和接受功能,就用了两个类就实现了,具体内容如下 说下思路把 主要有两个类 主界面类 和 蓝牙聊天服务类 . 首先创建线程 实际上就是创建BluetoothChatService() (蓝牙聊天服务类) 这个时候把handler 传过去 这样就可以操作UI 界面了,在线程中不断轮询读取蓝牙消息,当主界面点击发送按钮时 调用BluetoothChatService 的发送方法write 方法,这里的write 方法 使用了handler 发送消息,在主界面显示,另一个

  • Android仿微信语音聊天功能

    本文实例讲述了Android仿微信语音聊天功能代码.分享给大家供大家参考.具体如下: 项目效果如下: 具体代码如下: AudioManager.java package com.xuliugen.weichat; import java.io.File; import java.io.IOException; import java.util.UUID; import android.media.MediaRecorder; public class AudioManager { private

  • Android 基于Socket的聊天室实例

    Socket是TCP/IP协议上的一种通信,在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路.一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信. Client A  发信息给 Client B ,  A的信息首先发送信息到服务器Server ,Server接受到信息后再把A的信息广播发送给所有的Clients 首先我们要在服务器建立一个ServerSocket ,ServerSocket对象用于监听来自客户端的Socket连接,如果没有连接,它将一直处于等待

  • Android使用多线程进行网络聊天室通信

    TCP/IP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路.一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信了.Java对基于TCP协议的网络通信提供了良好的封装,Java使用Socket对象来代表两端通信接口,并通过Socket产生IO流来进行网络通信. 下面的程序Demo是实现一个简单的C/S聊天室的应用,每个客户端该包含两条线程:一条负责生成主界面,响应用户动作,并将用户输入的数据写入Socket对应的输出流中:另一条

  • Android编写简单的聊天室应用

    最近写了一个简单的聊天室应用,可以发送表情,更改头像这些功能.主要技术点就是怎样把表情图片放到textview等Ui控件中展示.这里废话不多说,下面是效果图: 这里主要讲下怎样把文本替换到表情,先说下思路,首先我们的图片是保存在本地资源目录drawable中而所有的资源文件都是R这个类来管理,所以我们可以利用正则表达式找出图片id包装成ImageSpan然后把ImageSpan放到SpannableString中,最后把SpannableString放入edittext中,下面是源码: pack

  • android socket聊天室功能实现

    前提概要 笔者很久之前其实就已经学习过了socket,当然也是用socket做过了聊天室,但是觉得此知识点比较一般,并无特别难的技术点,于是也并未深究. 然而近期一个项目中对socket的使用却让笔者感觉socket强大无比,可以实现诸多功能. 个人Socket体验 项目主要有关智能家居,需要实现多台手机同时对灯进行操作(开或者关),主要需要实现以下几点: 1.进入界面时获取所有灯的状态. 2.一台手机改变了灯的状态,其他的手机上可以有所显示. 3.硬件上改变了灯的状态(手动开关灯),所有手机上

  • Android使用Websocket实现聊天室

    最近的项目中要实现一个聊天的功能,类似于斗鱼TV的聊天室功能,与服务器端人商量后决定用WebSocket来做,但是在这之前我只知道Socket但是听都没有听过WebSocket,但是查看了相关的材料以后发现实现一个聊天室其实是很简单的!下面我们先来看看WebSocket. Autobahn|Android 是由Autobahn开发一个开源的Java/Android网络库,实现了WebSocket协议和Web应用程序消息传输协议来创建本地移动的WebSocket/ WAMP的客服端. WebSoc

  • Android高仿微信聊天界面代码分享

    微信聊天现在非常火,是因其界面漂亮吗,哈哈,也许吧.微信每条消息都带有一个气泡,非常迷人,看起来感觉实现起来非常难,其实并不难.下面小编给大家分享实现代码. 先给大家展示下实现效果图: OK,下面我们来看一下整个小项目的主体结构: 下面是Activity的代码: package com.way.demo; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import jav

随机推荐