读书笔记:
socket连接应用算是java底层连接了,如果有对应的解决,应避免,如线程的底层条件锁和内部对象锁,应避免,可以使用阻塞队列也实现同步。
Socket 感觉就是端口连接程序。
已经有的scoket测试工具是telnet.
SocketAddress 就是端口地址
|
有个子类为:InetSocketAddress
| |
| |
分InetAddress 端口
所以一个socket建立平时要InetSocketAddress,
它个构造方法有 Socket(String host, int port)
Socket(InetAddress address, int port)
也可以有先建立一个没有指定的,在事后指定,也有相关本地接口的。
获得一个连接 可以获得它的输入和输出流。
输入流为读取,输出流为向服务器端写入数据。
ServerSocket为实现服务器端类。
若想可以连续的接受客户端的连接可以
while(true)
{
socket=serverSocket.accept();
new Thread(new Runnable(socket)).start();
}
为每一个来的客户端提供一个线程为它服务。
半关闭的socket
socket.shutdownInput();
socket.shutdownOutput();
当建立一个Socket程序时,可能阻塞,同理当套接字读取数据也肯能阻塞,这时 可先建一个空的套接字,在设置hostName 和port 加上超时时间参数。
对于读取的阻塞可有SocketChannel 来解决,
package v2chapter03.InterruptibleSocketTest; import java.awt.*; import java.awt.event.*; import java.util.*; import java.net.*; import java.io.*; import java.nio.channels.*; import javax.swing.*; /** * This program shows how to interrupt a socket channel. * @author Cay Horstmann * @version 1.01 2007-06-25 */ public class InterruptibleSocketTest { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JFrame frame = new InterruptibleSocketFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } } class InterruptibleSocketFrame extends JFrame { public InterruptibleSocketFrame() { setSize(WIDTH, HEIGHT); setTitle("InterruptibleSocketTest"); JPanel northPanel = new JPanel(); add(northPanel, BorderLayout.NORTH); messages = new JTextArea(); add(new JScrollPane(messages)); interruptibleButton = new JButton("Interruptible"); blockingButton = new JButton("Blocking"); northPanel.add(interruptibleButton); northPanel.add(blockingButton); interruptibleButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { interruptibleButton.setEnabled(false); blockingButton.setEnabled(false); cancelButton.setEnabled(true); connectThread = new Thread(new Runnable() { public void run() { try { connectInterruptibly(); } catch (IOException e) { messages.append("\nInterruptibleSocketTest.connectInterruptibly: " + e); } } }); connectThread.start(); } }); blockingButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { interruptibleButton.setEnabled(false); blockingButton.setEnabled(false); cancelButton.setEnabled(true); connectThread = new Thread(new Runnable() { public void run() { try { connectBlocking(); } catch (IOException e) { messages.append("\nInterruptibleSocketTest.connectBlocking: " + e); } } }); connectThread.start(); } }); cancelButton = new JButton("Cancel"); cancelButton.setEnabled(false); northPanel.add(cancelButton); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { connectThread.interrupt(); cancelButton.setEnabled(false); } }); server = new TestServer(); new Thread(server).start(); } /** * Connects to the test server, using interruptible I/O */ public void connectInterruptibly() throws IOException { messages.append("Interruptible:\n"); SocketChannel channel = SocketChannel.open(new InetSocketAddress("localhost", 8189)); try { in = new Scanner(channel); while (!Thread.currentThread().isInterrupted()) { messages.append("Reading "); if (in.hasNextLine()) { String line = in.nextLine(); messages.append(line); messages.append("\n"); } } } finally { channel.close(); EventQueue.invokeLater(new Runnable() { public void run() { messages.append("Channel closed\n"); interruptibleButton.setEnabled(true); blockingButton.setEnabled(true); } }); } } /** * Connects to the test server, using blocking I/O */ public void connectBlocking() throws IOException { messages.append("Blocking:\n"); Socket sock = new Socket("localhost", 8189); try { in = new Scanner(sock.getInputStream()); while (!Thread.currentThread().isInterrupted()) { messages.append("Reading "); if (in.hasNextLine()) { String line = in.nextLine(); messages.append(line); messages.append("\n"); } } } finally { sock.close(); EventQueue.invokeLater(new Runnable() { public void run() { messages.append("Socket closed\n"); interruptibleButton.setEnabled(true); blockingButton.setEnabled(true); } }); } } /** * A multithreaded server that listens to port 8189 and sends numbers to the client, simulating a * hanging server after 10 numbers. */ class TestServer implements Runnable { public void run() { try { ServerSocket s = new ServerSocket(8189); while (true) { Socket incoming = s.accept(); Runnable r = new TestServerHandler(incoming); Thread t = new Thread(r); t.start(); } } catch (IOException e) { messages.append("\nTestServer.run: " + e); } } } /** * This class handles the client input for one server socket connection. */ class TestServerHandler implements Runnable { /** * Constructs a handler. * @param i the incoming socket */ public TestServerHandler(Socket i) { incoming = i; } public void run() { try { OutputStream outStream = incoming.getOutputStream(); PrintWriter out = new PrintWriter(outStream, true /* autoFlush */); while (counter < 100) { counter++; if (counter <= 10) out.println(counter); Thread.sleep(100); } incoming.close(); messages.append("Closing server\n"); } catch (Exception e) { messages.append("\nTestServerHandler.run: " + e); } } private Socket incoming; private int counter; } private Scanner in; private JButton interruptibleButton; private JButton blockingButton; private JButton cancelButton; private JTextArea messages; private TestServer server; private Thread connectThread; public static final int WIDTH = 300; public static final int HEIGHT = 300; }
程序在前十个输出时,点击cancel按钮 都会使客户端阻塞,但是在10后有一段时间服务器是阻塞的,这时候只有SocketChannel 可以立即使客户端阻塞,客户端阻塞不影响,服务器端,服务器端依然会继续执行直到,结束。如果在服务器端:
if (counter <= 10) out.println(counter);
{
System.out.println("休息中。。。");
Thread.sleep(100);
}
可以发现服务器端一直会输出,如果100结束后,服务器端关闭,但是不点击cannel 那么客户端 不会阻塞,会一直输出reading.也就是说 客户端和服务器不是统一的,要是服务器端线程阻塞了,那么会阻塞客户端(如果是channel就不会影响),但是客户端阻塞不会影响服务器端,