1:Socket与ServerSocket的交互java
2.Socket和ServerSocket介绍 编程
Socket 缓存
构造函数 服务器
Socket() 网络
Socket(InetAddress address, int port)throws UnknownHostException, IOException session
Socket(InetAddress address, int port, InetAddress localAddress, int localPort)throws IOException 多线程
Socket(String host, int port)throws UnknownHostException, IOException(最简单的链接方式) socket
Socket(String host, int port, InetAddress localAddress, int localPort)throws IOException ide
除去第一种不带参数的以外,其它构造函数会尝试创建与服务器的链接。若是失败会抛出IOException错误。若是成功,则返回Socket对象。 函数
InetAddress是一个用于记录主机的类,其静态getHostByName(String msg)能够返回一个实例,其静态方法getLocalHost()也能够得到当前主机的IP地址,并返回一个实例。
Socket(String host, int port, InetAddress localAddress, int localPort)构造函数的参数分别为目标IP、目标端口、绑定本地IP、绑定本地端口。
Socket方法
getInetAddress(); 远程服务端的IP地址
getPort(); 远程服务端的端口
getLocalAddress() 本地客户端的IP地址
getLocalPort() 本地客户端的端口
getInputStream(); 得到输入流
getOutStream(); 得到输出流
值得注意的是,在这些方法里面,最重要的就是getInputStream()和getOutputStream()了。
Socket状态
isClosed(); //链接是否已关闭,若关闭,返回true;不然返回false
isConnect(); //若是曾经链接过,返回true;不然返回false
isBound(); //若是Socket已经与本地一个端口绑定,返回true;不然返回false
ServerSocket
构造函数
ServerSocket()throws IOException
ServerSocket(int port)throws IOException
ServerSocket(int port, int backlog)throws IOException
ServerSocket(int port, int backlog, InetAddress bindAddr)throws IOException
注意点:
1. port服务端要监听的端口;backlog客户端链接请求的队列长度;bindAddr服务端绑定IP
2. 若是端口被占用或者没有权限使用某些端口会抛出BindException错误。譬如1~1023的端口须要管理员才拥有权限绑定。
3. 若是设置端口为0,则系统会自动为其分配一个端口;
4. bindAddr用于绑定服务器IP,为何会有这样的设置呢,譬若有些机器有多个网卡。
5. ServerSocket一旦绑定了监听端口,就没法更改。ServerSocket()能够实如今绑定端口前设置其余的参数。
3.实例前说明
Socket网络编程主要用于两台机器之间的数据传输,大体过程为:创建链接→信息传递→关闭链接。咱们能够理解为服务器(ServerSocket)和客户端(Socket),服务器提供链接服务,客户端连接服务器。由于服务器须要向多台客户端提供服务,因此须要一直保持监听状态,不断地监听客户端请求,在这个过程当中,ServerSocket一直处于阻断状态,直到有客户端链接,立刻返回一个Socket对象,而后经过IO流传输数据,在这个过程当中,当有数据传输的时候,IO流才被激活,其他时间都处于阻断状态,等待数据发送过来,而后进行处理。
注意:
不过,若是咱们不必不少的交互,只须要交互一次就能够了,就能够不在意这些,当关闭Socket的输入输出流的时候,Socket会将缓存池中的数据所有提交到另外一台机器。
最后最重要的,当咱们用完流的时候,必定要及时关闭,养成良好的习惯。
在下面的实例中,我经过多线程的方式保证服务器和客户端一直处于数据交互状态,而且使用线程池的方式维护线程。、
线程类:
package com.best.alivn.socketservice; import java.io.*; import java.net.Socket; import java.util.Scanner; /**让服务器处理与客户端通信放在线程中 * Created by Alivn on 2017/3/18. */ public class SessionThread implements Runnable{ private final Socket client; private static Integer Tag=0; public SessionThread(Socket client) { this.client = client; } @Override public void run() { //输出流 PrintWriter writer=null; //获取客户端输入流,获得客户端发来的消息 try { //读取客户端的数据 //读取到的一行数据 String line=null; //客户端发来的数据 //开启一个读线程 Thread write_thread= new Thread(new Runnable() { @Override public void run() { //输入流 InputStream inputStream=null; BufferedReader reader=null; try { while (true) { inputStream= client.getInputStream(); //为了提升效率,转换成字符流 reader=new BufferedReader(new InputStreamReader(inputStream)); String line=null; while ((line=reader.readLine())!=null) { System.out.println(line); } } } catch (IOException e) { //流异常 e.printStackTrace(); }finally { //关闭流 try { inputStream.close(); reader.close(); } catch (IOException e) { e.printStackTrace(); } } } }); write_thread.start(); //获取输出流,往客户端发送数据 writer=new PrintWriter(client.getOutputStream()); //客户端刚链接的时候,客户端反馈信息 String send_msg ="您已成功链接到服务器......--[Server]"; writer.println(send_msg); writer.flush(); //能够屡次发送 //从键盘输入 while ("1".equals("1")) { Scanner scanner=new Scanner(System.in); send_msg =scanner.nextLine()+"--[Server]"; writer.println(send_msg); //注意(咱们发送数据的时候,flush方法会提交咱们的数据,可是还不会发送,当数据达到必定容量才会发送, // 或者读到换行符的时候发送) writer.flush(); } } catch (IOException e) { //获取客户端输入流失败 e.printStackTrace(); }finally { //关闭流 try { client.shutdownInput(); client.shutdownOutput(); writer.close(); } catch (IOException e) { //关闭输入输出流失败 e.printStackTrace(); } } } }
服务器类:
package com.best.alivn.socketservice; import scala.actors.threadpool.ExecutorService; import scala.actors.threadpool.Executors; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /**服务器 * Created by Alivn on 2017/3/18. */ public class Server { //甚至端口号 private final static Integer PORT=8888; //设置开启的线程数 private final static Integer THREAD_SIZE=5; //建立线程池 private static ExecutorService executorService=null; public static void main(String[]args) { executorService = Executors.newFixedThreadPool(THREAD_SIZE); //建立服务器套接字 try { //建立三个线程放入到线程池中.... ServerSocket serverSocket=new ServerSocket(PORT); //开启服务器,一直处于监听的状态 System.out.println("[Server]:服务器已启动........."); while (true) { //服务器根据端口号,监听客户端连接, Socket client = serverSocket.accept(); System.out.println("[Server]:有客户端连接至服务器......."); //将交互放到线程中 SessionThread session=new SessionThread(client); //放入到线程池中 session.run(); executorService.execute(session); } } catch (IOException e) { //实例化服务器失败 e.printStackTrace(); } } }
package com.best.alivn.socketservice; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; /**客户端 * Created by Alivn on 2017/3/18. */ public class Client { private final static String host="localhost"; private final static Integer port=8888; public static void main(String[] args) { Socket socket=null; //输入流 BufferedReader reader=null; //建立客户端对象 try { //链接服务器 socket=new Socket(host,port); //客户端刚链接的时候,客户端反馈信息 //输出流 final PrintWriter writer=new PrintWriter(socket.getOutputStream());; String send_msg ="你好,我是小白......--[Client]"; writer.println(send_msg); writer.flush(); //开启一个线程,处理循环 Thread write_Stream= new Thread(new Runnable() { @Override public void run() { //循环输入数据 Scanner scanner=new Scanner(System.in); while ("1".equals("1")) { String send_msg=scanner.nextLine()+"--[Client]"; writer.println(send_msg); writer.flush(); } } }); write_Stream.start(); while ("1".equals("1")) { //获取输入流,得服务端的数据 reader=new BufferedReader(new InputStreamReader(socket.getInputStream())); String line=null; while ((line=reader.readLine())!=null) { System.out.println(line); } } writer.close(); } catch (IOException e) { //连接失败 文件读取失败 e.printStackTrace(); }finally { //关闭流 try { reader.close(); socket.shutdownInput(); socket.shutdownOutput(); } catch (IOException e) { e.printStackTrace(); } } } }