Android客户端与本地服务器Socket通信

炒沙作縻终不饱,缕冰文章费工巧。这篇文章主要讲述Android客户端与本地服务器Socket通信相关的知识,希望能为你提供帮助。
android客户端与本地服务器Socket通信
Socket服务器运行结果图??

Android客户端与本地服务器Socket通信

文章图片

一.客户端和服务器端的选择:
  • 客户端是我们手机端,关于服务器端,只要安装了JDK,自然就拥有通讯的功能,我们只需要在Eclipse或者MyEclipse中写好文章中服务器端的代码,运行起来即可,用accept()方法启动服务器端,等待客户端的连接,在未连接的情况下,服务器端处于堵塞的状态。
二.客户端注意事项
  • andriod客户端添加网络访问权限
    < uses-permission android:name="android.permission.INTERNET" />
  • 对Socket的操作放在非UI线程内进行
  • 要使用正确的IP地址和端口号端口号的范围是0~65535,1024一下的端口被系统分给了一些服务,在cmd窗口执行netstat -ano命令可以看到所有端口的使用情况
  • 真机进行调试(1、连接上手机,手机开启adb。步骤:设置> 应用程序> 开发> 选择USB调试; usb选项有些不可见,具体百度),指定Server的IP地址,此地址为局域网地址,如果是使用WIFI上网,则为PC机的WIFI IP。上图中连接的第二个就是示例。
    三.Socket通信
  • 利用ip地址+端口号唯一标示网络中的一个进程,能够唯一标示网络中的进程后,它们就可以利用socket进行通信。
  • socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用,实现进程在网络中通信。
  • socket是"打开—读/写—关闭"模式的实现(只能读取对方放在流中的数据),以使用TCP协议通讯的socket为例,其交互流程大概是这样子的
  • Socket有两种主要的操作方式:面向连接的和无连接的,即TCP和UDP。
    面向连接的Socket操作就像一部电话,Socket必须在发送数据之前与目的地的Socket取得连接,一旦连接建立了,Socket就可以使用一个流接口进行打开、读写以及关闭操作。并且,所有发送的数据在另一端都会以相同的顺序被接收。
  • 无连接的Socket操作就像一个邮件投递,每一个数据报都是一个独立的单元,它包含了这次投递的所有信息(目的地址和要发送的内容)。在这个模式下的Socket不需要连接目的地Socket,它只是简单的投出数据报。
    四.TCP连接与HTTP连接与Socket连接的区别
  • TCP连接与HTTP连接的区别
HTTP是基于TCP的,客户端往服务端发送一个HTTP请求时第一步就是要建立与服务端的TCP连接。
  • TCP连接与Socket连接的区别:
socket层只是在TCP/UDP传输层上做的一个抽象接口层,基于TCP协议的socket连接同样需要通过三次握手建立连接,是可靠的;基于UDP协议的socket连接不需要建立连接的过程,不过对方能不能收到都会发送过去,是不可靠的,大多数的即时通讯IM都是后者。
  • HTTP连接与Socket连接的区别
HTTP是短连接,Socket(基于TCP协议的)是长连接。尽管HTTP1.1开始支持持久连接,但仍无法保证始终连接。而Socket连接一旦建立TCP三次握手,除非一方主动断开,否则连接状态一直保持。
HTTP连接服务端无法主动发消息。决定二者分别适合应用在什么场景下。HTTP采用“请求-响应”机制,必须满足客户端发送消息在前,服务端回复在后。Socket连接双方类似peer2peer的关系,一方随时可以向另一方喊话。
  • 什么时候该用HTTP,什么时候该用socket
用HTTP的情况:双方不需要时刻保持连接在线,比如客户端资源的获取、文件上传等。
用Socket的情况:大部分即时通讯应用(QQ、微信)、聊天室、苹果APNs等。
五.socket代码客户端代码
public class MainActivity extends AppCompatActivity { //IP地址和端口号 public static String IP_ADDRESS = "192.168.1.106"; public static int PORT = 2346; //三个控件 EditText text = null; Button connect = null; TextView info = null; //handler Handler handler = null; Socket soc = null; DataOutputStream dos = null; DataInputStream dis = null; String messageRecv = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text = (EditText) findViewById(R.id.editText); connect = (Button) findViewById(R.id.buttonConnection); info = (TextView) findViewById(R.id.info); connect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new ConnectionThread(text.getText().toString()).start(); } }); handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); Bundle b = msg.getData(); //获取消息中的Bundle对象 String str = b.getString("data"); //获取键为data的字符串的值 info.append(str); } }; }//新建一个子线程,实现socket通信 class ConnectionThread extends Thread { String message = null; public ConnectionThread(String msg) { message = msg; }@Override public void run() { if (soc == null) { try { //Log.d("socket","new socket"); soc = new Socket(IP_ADDRESS, PORT); //获取socket的输入输出流 dis = new DataInputStream(soc.getInputStream()); dos = new DataOutputStream(soc.getOutputStream()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { dos.writeUTF(message); dos.flush(); messageRecv = dis.readUTF(); //如果没有收到数据,会阻塞 Message msg = new Message(); Bundle b = new Bundle(); b.putString("data", messageRecv); msg.setData(b); handler.sendMessage(msg); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }

`
服务器端代码
public class Server {ServerSocket serverSocket = null; public final int port = 2346; public Server(){//输出服务器的IP地址 try { InetAddress addr = InetAddress.getLocalHost(); System.out.println("local host:"+addr); serverSocket = new ServerSocket(port); System.out.println("0k"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }public void startService(){try { Socket socket = null; System.out.println("waiting..."); //等待连接,每建立一个连接,就新建一个线程 while(true){ socket = serverSocket.accept(); //等待一个客户端的连接,在连接之前,此方法是阻塞的 System.out.println("connect to"+socket.getInetAddress()+":"+socket.getLocalPort()); new ConnectThread(socket).start(); }} catch (IOException e) { // TODO Auto-generated catch block System.out.println("IOException"); e.printStackTrace(); } }//向客户端发送信息 class ConnectThread extends Thread{ Socket socket = null; public ConnectThread(Socket socket){ super(); this.socket = socket; }@Override public void run(){ try { DataInputStream dis = new DataInputStream(socket.getInputStream()); DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); while(true){ String msgRecv = dis.readUTF(); System.out.println("msg from client:"+msgRecv); dos.writeUTF("received:"+msgRecv); dos.flush(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }} } public static void main(String[] args) { // TODO Auto-generated method stub new Server().startService(); }}

代码的逻辑客户端 :
  1. 【Android客户端与本地服务器Socket通信】初始化控件,并绑定监听器,编写按钮的事件处理代码。
  2. 在事件处理代码中开启子线程,子线程中通过Sockt访问服务器。
  3. 利用异步消息处理机制,message对象将子线程的数据传回handle的处理方法更新UI。
服务端
  1. serversocket对象监听等待,利用循环当有客户访问就开启子线程处理传消息回客户端。(模拟器和手机同时通过局域网访问)
    最后的废话
  1. 搞计算机必须得有理论指导实践,否则只能像个没头苍蝇到处乱撞,我的计算机网络知识真的是一言难尽。
  2. 各大语言的官网是个好东西。丰富的资料和教程简直让人沉醉其中不能自拔。虽然比不上网络小说通俗易懂,但是引人入胜一点也不差。
  3. 不会的东西太多,用谷歌插件等工具列表,先解决主要的,平时有想法也可以记录。
  4. 用博客整理自己的知识,形成体系。看得再多不如编一遍。
PS. 集成了很多地方的知识点,官网,博主,就不一一记录原地址了。
2018-05-13 22:15:53 星期日








    推荐阅读