服务器端:

  实现一个简单的Hello服务,打印输出客户端IP地址到控制台,对任何连接的客户端都会发送一串字符(Hello, Java Socket)然后关闭与客户端连接。等待下一个客户端的连接请求到来。

  客户端:

  实现一个简单的Socket连接到Hello服务器端,接受服务器端发送过来的字节数据打印并输出内容到控制台。

  关键技巧:

  由于JAVA中提供非常多的输入与输出流API,导致很多初学者接触JAVA SOCKET编程时,由于对网络字节通信的本质缺乏了解,直接一个readline()去接受Socket字节流。但是由于发送一方并没有发送/r/n导致一直无法读到数据,这个是常见的一个错误。

  另外一些常见的错误包括没有初始化接受缓冲区导致字符乱码,没有按照读入接受到字节数重新组装,导致接受到的数据异常。所以代码演示了什么叫按字节发送与按字节接受,这个是网络编程中非常重要的概念与原则。让那些输入流println()方法与输出流readline()方法见鬼去吧,不是不好用,而是我建议你不要用,因为那些会妨碍你的网络编程本质的认识与理解。另外我要特别说明一下:有时候flush()真的不是必须的,除非你使用了带有缓冲的输入与输出流来读写字节。

  服务器端代码:


package com.gloomyfish.socket.tutorial.two;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class HelloService extends Thread {
 private ServerSocket serverSocket;
 public HelloService(int port) throws IOException {
  serverSocket = new ServerSocket(port);
 }

 public void run()
 {
  try {
   while(true)
   {
    System.out.println("Waiting for client on port " + serverSocket.getLocalPort());
    Socket client = serverSocket.accept(); // blocked & waiting for income socket
    System.out.println("Just connected to " + client.getRemoteSocketAddress());
    DataOutputStream dos = new DataOutputStream(client.getOutputStream());
    byte[] hello = "Hello, Java Socket".getBytes();
    dos.write(hello, 0, hello.length);
    dos.close();
    client.close();
   }
  } catch(Exception e) {
   e.printStackTrace();
  }
 }
 
 public static void main(String[] args) {
  try {
   HelloService service = new HelloService(9999);
   service.start();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
}
  服务器在端口9999监听并等待连接,使用Java Thread来实现服务器端启动。