三,socket通信
1.http://blog.csdn.net/kongxx/article/details/7288896這個人寫的關於socket通信不錯,循序漸進式的講解,用代碼示例說明,運用流和socket進行遠程通訊
2.最簡單的socket是一個服務端對應一個客戶端
server的寫法
- ServerSocket server = new ServerSocket(10000);
- Socket socket = server.accept();
- BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- PrintWriter out = new PrintWriter(socket.getOutputStream());
- while (true) {
- String msg = in.readLine();
- System.out.println(msg);
- out.println("Server received " + msg);
- out.flush();
- if (msg.equals("bye")) {
- break;
- }
- }
- socket.close();
client的寫法
- Socket socket = new Socket("localhost", 10000);
- BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- PrintWriter out = new PrintWriter(socket.getOutputStream());
- BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
- while (true) {
- String msg = reader.readLine();
- out.println(msg);
- out.flush();
- if (msg.equals("bye")) {
- break;
- }
- System.out.println(in.readLine());
- }
- socket.close();
3.複雜一點的就是多個客戶端同時訪問服務器。在客戶端使用循環啓動多個客戶端訪問同一服務端,在服務端只要server.accept()一接收到就新建線程,然後把把上面的讀寫操作放進線程內處理。
4.如果要利用socke傳遞對象,就要讓對象實現Serializable 序列化接口,使用ObjectInputStream和ObjectOutputStream進行序列化和反序列化
server的寫法
- ObjectInputStream is = null;
- ObjectOutputStream os = null;
- try {
- is = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
- os = new ObjectOutputStream(socket.getOutputStream());
- Object obj = is.readObject();
- User user = (User)obj;
- System.out.println("user: " + user.getName() + "/" + user.getPassword());
- user.setName(user.getName() + "_new");
- user.setPassword(user.getPassword() + "_new");
- os.writeObject(user);
- os.flush();
- } catch (IOException ex) {
- ObjectOutputStream os = null;
- ObjectInputStream is = null;
- try {
- socket = new Socket("localhost", 10000);
- os = new ObjectOutputStream(socket.getOutputStream());
- User user = new User("user_" + i, "password_" + i);
- os.writeObject(user);
- os.flush();
- is = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
- Object obj = is.readObject();
- if (obj != null) {
- user = (User)obj;
- System.out.println("user: " + user.getName() + "/" + user.getPassword());
- }
- } catch(IOException ex) {
5.如果還需要傳送時壓縮流再傳送,就要用到GZIPInputStream和GZIPOutputStream進行壓縮和反壓縮
server的寫法
- GZIPInputStream gzipis = null;
- ObjectInputStream ois = null;
- GZIPOutputStream gzipos = null;
- ObjectOutputStream oos = null;
- try {
- gzipis = new GZIPInputStream(socket.getInputStream());
- ois = new ObjectInputStream(gzipis);
- gzipos = new GZIPOutputStream(socket.getOutputStream());
- oos = new ObjectOutputStream(gzipos);
- Object obj = ois.readObject();
- User user = (User)obj;
- System.out.println("user: " + user.getName() + "/" + user.getPassword());
- user.setName(user.getName() + "_new");
- user.setPassword(user.getPassword() + "_new");
- oos.writeObject(user);
- oos.flush();
- gzipos.finish();
- } catch (IOException ex) {
- Socket socket = null;
- GZIPOutputStream gzipos = null;
- ObjectOutputStream oos = null;
- GZIPInputStream gzipis = null;
- ObjectInputStream ois = null;
- try {
- socket = new Socket();
- SocketAddress socketAddress = new InetSocketAddress("localhost", 10000);
- socket.connect(socketAddress, 10 * 1000);
- socket.setSoTimeout(10 * 1000);
- gzipos = new GZIPOutputStream(socket.getOutputStream());
- oos = new ObjectOutputStream(gzipos);
- User user = new User("user_" + i, "password_" + i);
- oos.writeObject(user);
- oos.flush();
- gzipos.finish();
- gzipis = new GZIPInputStream(socket.getInputStream());
- ois = new ObjectInputStream(gzipis);
- Object obj = ois.readObject();
- if (obj != null) {
- user = (User)obj;
- System.out.println("user: " + user.getName() + "/" + user.getPassword());
- }
- } catch(IOException ex) {
6.如果要加密傳送,就要使用加密後的socket,而不是使用加密的流
server的寫法,只需要對socket進行處理,流的處理不變
- ServerSocketFactory factory = SSLServerSocketFactory.getDefault();
- ServerSocket server = factory.createServerSocket(10000);
client的寫法
- SocketFactory factory = SSLSocketFactory.getDefault();
- socket = factory.createSocket("localhost", 10000);
7.使用nio實現socket通信
java.nio包是Java在1.4之後增加的,用來提高I/O操作的效率。在nio包中主要包括以下幾個類或接口:
* Buffer:緩衝區,用來臨時存放輸入或輸出數據。
* Charset:用來把Unicode字符編碼和其它字符編碼互轉。
* Channel:數據傳輸通道,用來把Buffer中的數據寫入到數據源,或者把數據源中的數據讀入到Buffer。
* Selector:用來支持異步I/O操作,也叫非阻塞I/O操作。
把對象轉爲字節數組- public static byte[] toBytes(Object object) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream oos = null;
- try {
- oos = new ObjectOutputStream(baos);
- oos.writeObject(object);
- byte[] bytes = baos.toByteArray();
- return bytes;
- ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
- ObjectInputStream ois = null;
- try {
- ois = new ObjectInputStream(bais);
- Object object = ois.readObject();
- return object;
- Selector selector = null;
- ServerSocketChannel serverSocketChannel = null;
- try {
- selector = Selector.open();
- serverSocketChannel = ServerSocketChannel.open();
- serverSocketChannel.configureBlocking(false);
- serverSocketChannel.socket().setReuseAddress(true);
- serverSocketChannel.socket().bind(new InetSocketAddress(10000));
- serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
- while (selector.select() > 0) {
- Iterator<SelectionKey> it = selector.selectedKeys().iterator();
- while (it.hasNext()) {
- SelectionKey readyKey = it.next();
- it.remove();
-
execute((ServerSocketChannel) readyKey.channel());
- private static void execute(ServerSocketChannel serverSocketChannel) throws IOException {
- SocketChannel socketChannel = null;
- try {
- socketChannel = serverSocketChannel.accept();
- MyRequestObject myRequestObject = receiveData(socketChannel);
- logger.log(Level.INFO, myRequestObject.toString());
- MyResponseObject myResponseObject = new MyResponseObject(
- "response for " + myRequestObject.getName(),
- "response for " + myRequestObject.getValue());
- sendData(socketChannel, myResponseObject);
- MyRequestObject myRequestObject = null;
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ByteBuffer buffer = ByteBuffer.allocate(1024);
- try {
- byte[] bytes;
- int size = 0;
- while ((size = socketChannel.read(buffer)) >= 0) {
- buffer.flip();
- bytes = new byte[size];
- buffer.get(bytes);
- baos.write(bytes);
- buffer.clear();
- }
- bytes = baos.toByteArray();
- Object obj = SerializableUtil.toObject(bytes);
- myRequestObject = (MyRequestObject)obj;
- sendData(SocketChannel socketChannel, MyResponseObject myResponseObject) throws IOException {
- byte[] bytes = SerializableUtil.toBytes(myResponseObject);
- ByteBuffer buffer = ByteBuffer.wrap(bytes);
- socketChannel.write(buffer);
client的寫法
- socketChannel = SocketChannel.open();
- SocketAddress socketAddress = new InetSocketAddress("localhost", 10000);
- socketChannel.connect(socketAddress);
- MyRequestObject myRequestObject = new MyRequestObject("request_" + idx, "request_" + idx);
- logger.log(Level.INFO, myRequestObject.toString());
- sendData(socketChannel, myRequestObject);
- MyResponseObject myResponseObject = receiveData(socketChannel);
-
logger.log(Level.INFO, myResponseObject.toString());
- private void sendData(SocketChannel socketChannel, MyRequestObject myRequestObject) throws IOException {
- byte[] bytes = SerializableUtil.toBytes(myRequestObject);
- ByteBuffer buffer = ByteBuffer.wrap(bytes);
- socketChannel.write(buffer);
-
socketChannel.socket().shutdownOutput();
- private MyResponseObject receiveData(SocketChannel socketChannel) throws IOException {
- MyResponseObject myResponseObject = null;
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
- byte[] bytes;
- int count = 0;
- while ((count = socketChannel.read(buffer)) >= 0) {
- buffer.flip();
- bytes = new byte[count];
- buffer.get(bytes);
- baos.write(bytes);
- buffer.clear();
- }
- bytes = baos.toByteArray();
- Object obj = SerializableUtil.toObject(bytes);
- myResponseObject = (MyResponseObject) obj;
- socketChannel.socket().shutdownInput();
上面的例子都需要先運行server再運行client。