读书笔记:
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就不会影响),但是客户端阻塞不会影响服务器端,