Socket之客户端Socket

来源:互联网 发布:组合楼板计算软件 编辑:程序博客网 时间:2024/06/04 18:53
背景:
在互联网上,数据按有限大小的包在网上传输,这些包称为数据报(datagram).每个包包含一个首部和一个有效载荷。首部包含发送的地址和端口、包来自的地址和端口、检验和以及其他管理信息。有效载荷包含数据本身,由于数据长度有限,通常将数据分解为多个包,在接收方在重新组合。在传输的过程,包可能会丢失、数据被破话,需要重传或者各个包重新排序。而这个过程是很繁重的工作,需要大量负载的代码。所以这时候,Socket就出现了。Socket允许程序员将网络看作是另外一个可以读写字节的流,掩盖了网络底层细节的实现,如错误检查、包大小、包分解、包重传、网络地址等。
Socket的使用:
Socket是两台主机之间的一个连接,七个基本步骤:
  1. 连接远程主机
  2. 发送数据
  3. 接收数据
  4. 关闭连接
  5. 绑定端口
  6. 监听入站数据
  7. 在绑定端口接受来自远程服务器的连接
客户端Socket创建:1、使用构造函数创建一个新的Socket 2、Socket尝试连接远程主机。一旦建立连接(全双工),客户端和服务器就可以互通数据,现在大多数网络协议都支持重复2、3步骤,如HTTP 1.1和FTP协议。
客户端Socket
每个客户端Socket构造函数指定要连接的主机和端口。主机可以是String或IntelAddress,远程端口指定为1到65535之间的int值。

public Socket(String host, int port) throws UnknownHostException, IOException
publicSocket(InetAddress address,int port) throws IOException
从服务器读数据
Socket socket=new Socket("time.nist.gov",13);
这里"time.nist.gov"是域名,要连接的远程服务器,13是端口,通过该Socket连接国家标准与技术研究院的daytime服务器,获取当前时间,创建Socket实例,会自动建立连接。连接成功后,可调用获取输入输出流和设置相应的属性,从而实现和服务器互通数据。

String url="time.nist.gov";

try( Socket socket=new Socket(url,13)){
    socket.setSoTimeout(10000);
    InputStream is=socket.getInputStream();
    InputStreamReader isr=new InputStreamReader(is);
    BufferedReader br=new BufferedReader(isr);
    StringBuilder sb=new StringBuilder();
    char[] bytes = new char[1204];
    while ((br.read(bytes))!=-1){
        sb.append(bytes);
    }
    Log.e("192",sb.toString());
    br.close();
    isr.close();
    is.close();
catch (UnknownHostException e) {
    e.printStackTrace();
catch (IOException e) {
    e.printStackTrace();
}
close()方法会同时关闭Socket的输入输出流,有时可能只希望关闭一半,半关闭Socket,即只关闭输入流或输出流,shutdownInput()和shutdownOutput()方法可以只关闭连接的一般。
向服务器写数据
那么,如何使用客户端Socket向服务器写入数据呢?先看代码,再分析

//获得原始输出流
OutputStream os=socket.getOutputStream();
//转为更方便的字符输出流
OutputStreamWriter writer=new OutputStreamWriter(os,"UTF-8");
//转为缓冲流
BufferedWriter bf=new BufferedWriter(writer);
//写入数据
bf.write("wwww.androidzhang.com\r\n");
//刷出所有数据
writer.flush();

可知,通过Socket的getOutputStream()方法获取输出流,最后封装为BufferWriter,向服务器写入www.androidzhang.com字符串,这样就完成了客户端Socket向服务器写入数据。操作和普通的输出流没什么区别。
上面构造的Socket对象的同时,都会同时打开与远程主机的一个网络连接。那么有没有办法构造但不连接呢,调用Socket的无参构造函数即可。

try {
    //构造Socket但不连接
    Socket socket = new Socket();
    //构建Socket地址
    SocketAddress address = new InetSocketAddress("www.androidzhang.com"80);
    //连接远程主机
    socket.connect(address);
    //使用socket
catch (IOException e) {
    e.printStackTrace();
}
也就是将操作进行分解,从而控制Socket的步骤。这里的SocketAddress表示一个连接端点,主要用途为暂时的Socket连接信息提供方便的存储。通过Socket的getRemoteSocketAddress()方法和getLocalSocketAddress()方法可以分别获取远程的SocketAddress和本地SocketAddress,从而进一步获得端口,主机名,地址等信息。
Socket相关方法
获取远程地址:
getIntelAddress()
获取远程端口:
getPort()
获取本地地址:
getLocalAddress()
获取本地端口:
getLocalPort()
判断Socket是否打开:
boolean connected = socket.isConnected && ! socket.isClosed();