本文系作者原创,转载请附原文地址,谢谢。

原文地址: http://blog.csdn.net/a774057695/article/details/47039433
文章末尾提供本文中的源码下载链接,需资源积分1分,人艰不拆,下载后评论资源可获系统返回积分=无损!



前言:

关于什么是socket通信,本篇文档中不进行解释,不甚清楚的可以去百科查找,日后得空我也会整理相关的内容。

本文是对上一篇关于消息推送的文章的补充,此处给出快速链接:http://blog.csdn.net/a774057695/article/details/47024887

本篇书写的目的:

1.让android客户端和服务器端实现socket通信,且demo需实现双向

2.为实现服务器向客户端推送消息奠定基础

特别说明:

1.服务器端利用pc机运行apach服务器模拟

2.Pc集成xampp环境

3.服务器端eclipse编译,java实现

4.客户端使用真机调试(使用模拟器需要对源码进行修改,因为没有尝试,所以没有给出示例代码,使用模拟器调试出错的请留意该点)

5.手机和pc加入同一域,至少连入同一台路由器,使用wifi共享的方法本文不提供技术支持、不保证其可行性。

功能概述:

l 服务器端:

主函数实现:阻塞的代码段等待socket连接、启动线程为socket连接提供应答;

互动线程(暂且这样称呼):实现收到客户端消息后进行反馈

单向线程(暂且这样称呼):实现接受控制台输入并向客户端发送

连接断开删去该条socket

l 客户端:

实现向服务器端建立socket连接

启动线程监听服务器发送的消息、并反馈UI显示

将本地消息发往服务器

代码结构:

服务器端:(主要)

|-- MyServer

|--src

|--[package]

|--MyServer.java

|--ServerThread.java

|--Thread2.java

客户端:(主要)

|--MultiThreadClient

|--src

|--[package]

|--ClientThread.java

|--MainActivity.java

|--res

|--layout

|--activity_main.xml

|--AndroidManifest.xml

代码示例及关键点:

l 服务器端:

MyServer.java

import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;public class MyServer {   //定义保存所有Socket的ArrayList   public static ArrayList<Socket> socketList = new ArrayList<Socket>();   /**    * @param args    * @throws IOException    */   public static void main(String[] args) throws IOException {      // param 端口号      ServerSocket ss = new ServerSocket(30000);      while(true){         //此代码会阻塞,将一直等待别人连接         Socket s = ss.accept();         socketList.add(s);         /*每当客户端连接后启动一条ServerThread线程为该客户端服务*/         new Thread(new ServerThread(s)).start();         new Thread(new Thread2(s)).start();      }   } }

此处我们需要留意的是端口号,第一不要去使用系统关键服务的端口号,第二我们要注意客户端中的端口号需要匹配,在后面我们还会提及。

ServerThread.java

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStream;import java.net.Socket; public class ServerThread implements Runnable {    //定义当前线程所处理的Socket   Socket s = null;   //该线程所处理的Socket所对应的输入流   BufferedReader br = null;   public ServerThread(Socket s) throws IOException {      this.s = s;      //初始化该Socket对应的输入流      br = new BufferedReader(new InputStreamReader(s.getInputStream(),            "utf-8"));   }    @Override   public void run() {      try      {         String content = null;         //采用循环不断从Socket中读取客户端发送过来的数据         while((content = readFromClient())!=null){            //遍历socketList中的每个Socket            //将读到的内容向每个Socket发送一次            for(Socket s : MyServer.socketList){                OutputStream os = s.getOutputStream();                //简单处理模拟应答                os.write((content + "——返回自服务器\n").getBytes("utf-8"));            }         }      }catch (IOException e) {         e.printStackTrace();      }   }   /**    * 读取客户端数据    * @return    */   public String readFromClient()   {      try{         return br.readLine();      }catch(IOException e){   //如果捕捉到异常,表明该Socket对应的客户端已经被关闭         //删除该Socket         MyServer.socketList.remove(s);      }      return null;   } }

这里也没有太多值得注意的,这条线程是实现对客户端应答,当客户端向服务器发出消息,服务器收到后进行反馈,这里我们只是对原来的内容进行了简单的处理,可以按照服务器-客户端之间的约定,实现更有意义的事情。

当连接断开时,删除该socket

Thread2.java

import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStream;import java.net.Socket;  public class Thread2 implements Runnable {    //定义当前线程所处理的Socket   Socket s = null;   //该线程所处理的Socket所对应的输入流   BufferedReader br = null;    public Thread2(Socket s) throws IOException {      this.s = s;      //初始化该Socket对应的输入流      br = new BufferedReader(new InputStreamReader(s.getInputStream(),            "utf-8"));   }     /**    * 读取控制台输入    * */   private void readConsole() {        //数组缓冲        byte[] b = new byte[1024];        //有效数据个数        int n = 0;        try{         while(true){              //提示信息              System.out.println("请输入:");              //读取数据              n = System.in.read(b);              //转换为字符串              String str = new String(b,0,n - 2);            //发送到客户端             for(Socket s : MyServer.socketList){                OutputStream os = s.getOutputStream();                os.write(("服务器发送"+str + "\n").getBytes("utf-8"));            }              //判断是否是quit              if(str.equalsIgnoreCase("quit")){                        break; //结束循环              }              //回显内容              System.out.println("输入内容为:" + str);             }        }catch(Exception e){}   }      @Override   public void run() {      readConsole();        }}

这条线程实现读取控制台输入内容并向客户端发送,这里我们没有关心连接断开,这与demo的目的不冲突,但是投入生产时还是应当注意。

l 客户端:

AndroidManifest.xml

创建一个应用,首先做得事情不是在默认打开的布局文件中进行布局,而是规划一下需要哪些权限,并在配置文件中添加!

本处我们需要申请Internet权限:

<uses-permission android:name="android.permission.INTERNET"/>

手打的朋友请注意:是uses,不是user!

activity_main.xml

预览:(真的太大,求调大小功能)


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/RelativeLayout1"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="bottom"    android:orientation="vertical" > <!--个并不美观的布局 -->    <EditText        android:id="@+id/show"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_above="@+id/linearLayout1"        android:layout_alignParentLeft="true"        android:cursorVisible="false"        android:gravity="top" />     <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/linearLayout1"        android:orientation="horizontal"        android:weightSum="5"        android:layout_alignParentBottom="true" >         <EditText            android:id="@+id/input"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="5"             >            <requestFocus />        </EditText>         <Button            android:id="@+id/send"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:text="send" />    </LinearLayout> </RelativeLayout>

MainActivity.java

package com.example.multithreadclient; import java.io.IOException;import java.io.OutputStream;import java.io.UnsupportedEncodingException;import java.net.Socket; import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.os.Handler;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.TextView; public class MainActivity extends Activity {        EditText input, show;       TextView mode;       Button send,smode,cmode;       OutputStream os;       Handler handler;        @Override       protected void onCreate(Bundle savedInstanceState) {              super.onCreate(savedInstanceState);              setContentView(R.layout.activity_main);              input = (EditText) findViewById(R.id.input);              send = (Button) findViewById(R.id.send);              show = (EditText) findViewById(R.id.show);                           handler = new Handler() {                     public void handleMessage(android.os.Message msg) {                            if (msg.what == 0x123) {                                   show.append("\n" + msg.obj.toString());                            }                     };              };              new AsyncTask<String, String, String>(){                      @Override                     protected String doInBackground(String... params) {                            // TODO Auto-generated method stub                            Socket s;                            try {                                   /**@ param param1 param2                                    * param1: 服务器ip地址,本例中,即pc机的ip地址 cmd输入ipconfig -all可查询                                    * param2:端口号 注意和服务器源码中的匹配本                                    *例中30000                                    * */                                   s = new Socket(param1,param2);                                   //客户端启动ClientThread线程,不断读取来自服务器的数据                                   new Thread(new ClientThread(s, handler)).start();                                   os = s.getOutputStream();                            } catch (Exception e) {                                   e.printStackTrace();                            }                            return null;                     }                                  }.execute("");                           send.setOnClickListener(new OnClickListener() {                      @Override                     public void onClick(View v) {                            // TODO Auto-generated method stub                            try {                                   //将用户在文本框中输入的内容写入网络                                   os.write((input.getText().toString() + "\r\n")                                                 .getBytes("utf-8"));                                   input.setText("");                            } catch (IOException e) {                                   // TODO Auto-generated catch block                                   e.printStackTrace();                            }                     }              });       }             @Override       protected void onDestroy() {              super.onDestroy();              try {                     os.write("".getBytes("utf-8"));              } catch (UnsupportedEncodingException e) {                     // TODO Auto-generated catch block                     e.printStackTrace();              } catch (IOException e) {                     // TODO Auto-generated catch block                     e.printStackTrace();              }       }}

值得特别注意的就是两个参数!在注释中已经说得很明白了,第一个是pc机的ip,第二个是服务器约定的端口号。使用模拟器进行调试需要修改ip,我印象中是10.0.2.2,而127.0.0.1会被认为是android模拟器本身。

ClientThread.java

package com.example.multithreadclient; import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket; import android.os.Handler;import android.os.Message; public class ClientThread implements Runnable {        private Socket s;  //该线程负责处理的Socket       private Handler handler;       //该线程所处理的Socket对应的输入流       BufferedReader br = null;        public ClientThread(Socket s, Handler handler) throws IOException {              this.s = s;              this.handler = handler;              br = new BufferedReader(new InputStreamReader(s.getInputStream()));       }        @Override       public void run() {              // TODO Auto-generated method stub              try {                     String content = null;                     //不断读取Socket输入流中的内容                     while ((content = br.readLine()) != null) {                            //每当读到来自服务器的数据后,发送消息通知程序界面显示数据                            Message msg = new Message();                            msg.what = 0x123;                            msg.obj = content;                            handler.sendMessage(msg);                     }              } catch (Exception e) {                     e.printStackTrace();              }        }}


此处没有特别关注的地方

运行测试:

调试android应用,将其安装到手机,只是想先装上去而已

运行xampp panel 启动apach服务

Eclipse中运行服务器端程序

重新启动手机端的客户端程序——只是需要服务器先启动,客户端再连接而已。

你可以在eclipse的console中输入想要发送的消息,回车会被去掉,输入quit回车可以停止之,然并卵

你也可以在手机端发送消息等待回传消息

截图就不附了


本文系作者原创,转载请附原文地址,谢谢。

原文地址: http://blog.csdn.net/a774057695/article/details/47039433
本文中的源码下载链接:http://download.csdn.net/detail/a774057695/8929341需资源积分1分,人艰不拆,下载后评论资源可获系统返回积分=无损!


更多相关文章

  1. 万字长文带你了解最常用的开源 Squid 代理服务器
  2. Nginx系列教程(一)| 手把手教你在Linux环境下搭建Nginx服务
  3. Nginx系列教程(二)| 一文带你读懂Nginx的正向与反向代理
  4. Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
  5. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  6. Android中有关Handler的使用(一)
  7. Android怎样停止AsyncTask和Thread
  8. [Android] Handler详解
  9. Android(安卓)Service 详解二:创建一个service

随机推荐

  1. android 使用websocket 实现简单的聊天。
  2. Android中GUI系统的Event路由机制
  3. The source attachment does not contain
  4. 【Java&Android开源库代码剖析】のAndroi
  5. android之activity切换
  6. Ubuntu安装低版本gcc
  7. Android培训班(50)
  8. android模仿移动MM Tab 点击 背景 滑动效
  9. android开发每日汇总【2011-10-04】
  10. Android(安卓)如何获取 umeng 的 渠道信