Socket的分析与使用
来源:互联网 发布:c语言 socket服务端 编辑:程序博客网 时间:2024/06/05 01:00
Socket可以说是android中跨进程通信的一种方式,有时候也可以用于简单的网络传输,对于套接字连接,需要了解ServerSocket和Socket这两个流式套接字,这两个类的具体实现是有PlainSocketImpl实现的,它是SocketImpl的子类,同时SocketImpl也是一个是实现了SocketOption的抽象类。所以要了解Socket怎么用,就需要对这些都了解。下面介绍。
一、ScoketOptions
SocketOptions是为Scoket定义的一个用于设置或者获取Socket各种属性(比如 连接超时,缓冲区大小......)的接口。这里面包含了很多重要的Socket属性信息以及两个get,set方法,了解它对于以后使用Socket进行连接通讯,可以更加得心应手。现在按照笔者认为的便于大家理解的顺序来讲解。
①、设置SocketOptions里的各数据项的值:
public void setOption(int optID, Object val) throws SocketException;
用于将val值设置给指定的optID对象。
②、获取SocketOptions的各项数据值:
public Object getOption(int optID) throws SocketException;
获取SocketOptions中指定optID的值。
接下来你会看到一堆静态常量,你可能会奇怪的是,final定义的常量为什么可以重新设置值。这里先打个预防针,因为SocketOptions定义的常量都是默认的常量值,也就是说你完全可以不理这些,你自己直接使用系统的值,但如果你要设置某个具体数据的值,可以通过setOptions来设置,这个方法的具体实现是在AcstractPlainSocketImpl里面,是根据optID来设置optID对应的局部变量的值。因此,我们调用此方法并不是直接修改optID的静态常量值,这点从ScoketOptions是一个接口就可以看出。下面介绍各个optID代表的意思。
③、public static final int SO_LINGER = 128
表示如果在关闭Socket的时候仍然有缓冲数据未发送,那么Socket在关闭之前应该等待的时间,128表示128秒。此值可以设为0,表示无论缓冲区是否还有数据未发送,当前的Socke都会马上关闭,并且close方法会立即执行。此值应该介于0-65535之间,大于65535将当作65535来对待。如果在指定的等待时间内,数据发送完毕,那么socket会正常关闭,否则将会强制关闭。
④、public static final int SO_TIMEOUT = 4102
表示连接超时时间(即在读取操作的时间不可以超过此时间值),如果是0表示没有连接超时时间,此值不可以是负值,单位是毫秒。
⑤、public static final int TCP_NODELAY = 1
指示数据是马上发送还是先缓存之后在发送,如果是马上发送会导致效率底下,缓存发送会有很高的效率。
⑥、public static final int SO_KEEPALIVE = 8
表示Socket是否发送检测连接是否存活的消息。如果在链接过程中,一直未得到对方的应答,socket会一直尝试连接,直到连接成功。
SocketOptions定义了连接的基本属性,接下来解析SocketImpl这个抽象类,此类定义了socket基本的方法,了解了这些方法的含义,有助于更好的了解Socket,因为Socket内部的操作是通过SocketImpl的子类来实现的。
二、SocketImpl
SocketImpl是一个抽象类,是所有流式套接字的基础,流式套接字主要有两个ServerSocket和Socket,前者一般用于服务端后者用于客户端,作为服务端通常会嵌入两种流式套接字,分别为ServerSocket表示用于监听客户端的对象,一旦连接成功会返回一个Socket,代表客户端的连接对象。而SocketImpl封装了一些上述流式套接字会用到的基本方法,下面来了解:
①、端口,ip
protected InetAddress address
protected int port;
protected int localport
②、监听:
protected abstract void accept(SocketImpl newSocket) throws IOException;
③、绑定:
protected abstract void bind(InetAddress address, int port) throws IOException;
④、关闭连接:
protected abstract void close() throws IOException;
⑤、建立连接:
protected abstract void connect(String host, int port) throws IOException;
此方法用于将socket对象连接到远程主机地址和端口号。
⑥、获取远程地址:
protected InetAddress getInetAddress()
获取当前socket对象的远程连接对象的地址。
⑦、获取输入流:
protected abstract InputStream getInputStream()
获取当前Socket对象的输入流,用来读取数据。
⑧、获取本地绑定端口:
protected int getLocalPort()
⑨、获取输出流:
protected abstract OutputStream getOutputStream()
获取socket对象的输出流,用于发送数据。
⑩、获取远程连接对象的端口号
protected int getPort()
more:关闭输入流输出流:
protected void shutdownInput() throws IOException
protected void shutdownOutput() throws IOException
关闭输入流输出流。
SocketImpl是一个抽象类,它只是定义了用于scoket通信机制的基本方法,在Android中,默认使用的是PlainSocketImpl来实现基本的通讯细节。如果有需要可以自己实现SocketImpl的通信细节,可以参考PlainSocketImpl。下面讲解Socket。
三、Socket
public Socket()
public Socket(String dstName, int dstPort)
两个构造函数都是使用了默认的SocketImpl的子类PlainSocketImpl的基本实现机制。后者还指定了远程连接对象的地址和端口。
public synchronized void close()
public InetAddress getInetAddress()
public InputStream getInputStream()
public OutputStream getOutputStream()
获取输入流和输出流,输入流用来读取数据,输出流用来发送数据。
public void shutdownInput()
public void shutdownOutput()
前者用于关闭输入流,一旦关闭了,将不再接收任何远程对象发送的信息。如果在关闭了输入流之后又进行读取数据的操作会导致异常。
⑥、绑定本地地址
public void bind(SocketAddress localAddr)
用于将socket绑定到本地地址和本地端口,如果localAddr为null的话,将会从本地地址寻找任一可使用端口作为绑定端口。
⑦、远程连接
public void connect(SocketAddress remoteAddr, int timeout)
连接到指定地址的远程对象,timeout表示连接超时时间,可以传值0,0表示无穷大的连接超时时间。
综述,对于ScoketOptions里面提到的很多属性,可以同个scoket.setXXX的方法来设置。可以看到scoket封装了很多基本的方法,使用socket通信的时候,我们只需要关注scoket(如果需要自定义SokcetImpl,请参考plainSocketImpl)这一块就行了。下面再来了解ServerSocket.
四、ServerSocket
ServerSocket表示一个用于等待客户端连接的服务端对象,一旦有客户端连接成功,就可以进行一些适当的回应。同时,ServerSocket的socket通信机制也是又ScoketImpl来实现的,默认的是PlainSockImpl。ServerSocker用法上和Socket有很大相似之处,但也有不用的地方,比如ServerSocket拥有自己的阻塞队列用于接收客户端请求。下面讲解:
①构造函数:
public ServerSocket(int port) throws IOException
public ServerSocket(int port, int backlog) throws IOException
前者用于创建一个用指定端口指定的ServerSocket对象,后者顺带制订了阻塞队列的长度,这个值默认是50.一旦接受的客户端连接对象数量超过了这个值,那么所有超过这个值得连接对象都会被拒绝。
②、监听客户端连接:
public Socket accept() throws IOException
用于监听客户端连接,此方法会导致线程阻塞,直到有新的连接进来,并且会返回一个socket对象,用于和客户端通信。
③、关闭监听:
public void close() throws IOException
调用此方法后,任何尝试建立连接都会失败。
ServerSocket很大程度上和Socket相似,这里就介绍这么多,接下来用一个例子讲解。
ServiceClient:
package com.example.hy.second.Socket;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.os.PersistableBundle;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import com.example.hy.second.R;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.io.StringReader;import java.net.Socket;/** * Created by X1Carbon on 2016/6/16. */public class ServiceClient extends Activity { private EditText etContent; private TextView tvMsg; private Button btSend; private final String path = "127.0.0.1"; private Socket socket = null; private BufferedReader reader = null; private PrintWriter writer = null; private final int SOCKET_CONNECTED = 1, RECEIVED_MSG = 2; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case SOCKET_CONNECTED: btSend.setEnabled(true); break; case RECEIVED_MSG: tvMsg.setText(tvMsg.getText().toString() + "来自服务端的消息:" + msg.obj +"\n"); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.socket_layout); etContent = (EditText) findViewById(R.id.etContent); tvMsg = (TextView) findViewById(R.id.tvMsg); btSend = (Button) findViewById(R.id.btSend); Intent intent = new Intent(ServiceClient.this, ServiceSocket.class); startService(intent); clientThread.start(); } private Thread clientThread = new Thread(new Runnable() { @Override public void run() { while (socket == null) { try { Message message=handler.obtainMessage(); socket = new Socket(path, 8887); reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true); handler.sendEmptyMessage(SOCKET_CONNECTED); while (!ServiceClient.this.isFinishing()) { readReply(); } } catch (Exception e) { e.printStackTrace(); } finally { CloseUtils.close(reader); CloseUtils.close(writer); } } } }); private void readReply() { if (reader != null) { try { String msg = reader.readLine(); if(msg!=null) Message.obtain(handler, RECEIVED_MSG, msg).sendToTarget(); } catch (IOException e) { e.printStackTrace(); } } } public void send(View view) { if (writer != null) { String msg = etContent.getText().toString(); writer.println(msg); tvMsg.setText(tvMsg.getText().toString() + "我发送了:" + msg + "\n"); } else { Toast.makeText(ServiceClient.this, "尚未链接", Toast.LENGTH_LONG).show(); } } @Override protected void onDestroy() { super.onDestroy(); try { socket.shutdownOutput(); socket.shutdownInput(); socket.close(); } catch (Exception e) { e.printStackTrace(); } }}
serviceSocket:
package com.example.hy.second.Socket;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.support.annotation.Nullable;import android.util.Log;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;import java.util.Random;/** * Created by X1Carbon on 2016/6/16. */public class ServiceSocket extends Service { private boolean isServiceClose = false; @Nullable @Override public IBinder onBind(Intent intent) { return null; } private Thread serviceThread = new Thread(new Runnable() { @Override public void run() { try { ServerSocket server = new ServerSocket(8887); while (!isServiceClose) { final Socket socket = server.accept(); new Thread(new Runnable() { @Override public void run() { processSocket(socket); } }).start(); } } catch (Exception err) { } } }); private synchronized void processSocket(Socket socket) { BufferedReader reader = null; PrintWriter writer = null; Random random = new Random(); try { reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true); while (!isServiceClose) { String clientMsg = reader.readLine();//当收到的信息为null说明客户端关闭连接了 Log.i("service", "收到来自客户端的消息:" + clientMsg); if (clientMsg == null) break; else { writer.println(clientMsg.length()); } } } catch (IOException e) { e.printStackTrace(); } finally { CloseUtils.close(reader); CloseUtils.close(writer); try { socket.shutdownInput(); socket.shutdownOutput(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } @Override public void onDestroy() { super.onDestroy(); isServiceClose = true; } @Override public void onCreate() { super.onCreate(); serviceThread.start(); }}
closeUtils:
package com.example.hy.second.Socket;import java.io.Closeable;import java.io.IOException;/** * Created by X1Carbon on 2016/6/16. */public class CloseUtils { public static void close(Closeable obj) { if (obj != null) try { obj.close(); } catch (IOException e) { e.printStackTrace(); } }}
布局:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <EditText android:id="@+id/etContent" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入内容" /> <Button android:id="@+id/btSend" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="send" android:enabled="false" android:text="发送" /> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/tvMsg" android:layout_width="match_parent" android:layout_height="match_parent" /> </ScrollView></LinearLayout>
运行效果:
接下来读者好好体会一下(写的有点烦,所以没怎么解释,不过应该看得懂)。
---------文章写自:HyHarden---------
--------博客地址:http://blog.csdn.net/qq_25722767-----------
---------文章写自:HyHarden---------
--------博客地址:http://blog.csdn.net/qq_25722767-----------
- Socket的分析与使用
- socket 中select的使用与分析
- 第一个使用socket的源码分析
- HTTP与socket的介绍与区别分析
- socket的定义与使用场景
- C++ socket shutdow 与 close 的使用
- Socket的原理简析与使用
- C#Socket的使用与示例
- 深入php socket的讲解与实例分析
- Socket 原理与使用
- RabbitMQ的使用与分析
- ThreadPoolExecutor的分析与使用
- nanomsg的使用与分析
- WebView的分析与使用
- Bitmap 的分析与使用
- ThreadLocal的分析与使用
- Bitmap的分析与使用
- ClassLoader的分析与使用
- php 获取当前毫秒时间
- Cookie禁用了,Session还能用吗?
- JDBC 连接数据库
- 公众号吸粉实操之qq群吸粉
- mysqldump导出--数据+结构+(函数+存储过程)
- Socket的分析与使用
- 周期性任务执行实现模板线程类
- java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).
- leetcode 377 Combination Sum IV 动态规划
- eclipse最有用快捷键整理(zhuan)
- MFC界面库BCGControlBar v25.0新功能详解六:属性网格和其他
- Page_load事件 Page.IsPostBack属性
- 二分查找模板
- JSPatch演讲视频