网络编程中的若干盲点

  • 服务器套接字和连接套接字的区别

        其实看UNP的时候,我根本没有仔细思考这两个概念的区别。然后学习Java网络编程的时候就很好奇,Java的ServerSocket和Socket设计的初衷是什么呢?其实在Socket的本地api并没有对这两者做很大区分。事实上,他们都是使用socket()调用创建的,所以他们的内存布局应该都是一样的。两者的正真区别体现在listen调用和connect调用(两者都可以使用bind调用,虽然连接套接字的很少会这样使用)。一个非常直观的概念是服务器套接字是一个由本地端口和本地ip地址组成的二元组(严格来说还包含协议),而连接套接字这是由本地端口、本地ip地址、远程端口和远程ip地址组成的四元组。

  • 主动连接套接字也可使用bind绑定本地ip和端口

        客户端socket也可以主动绑定ip地址和端口,一个很常见的应用就是主动模式的ftp协议。ftp服务器的数据连接socket是主动绑定的20端口,然后主动连接客户端的数据端口。在多个回话并行的情况下,多个连接socket的端口都是20,但是由于客户ip和端口不同,所以并不会冲突。

  • 连接套接字可以同时打开

        在大名鼎鼎的tcp状态转移图中,有一个非常比较奇怪的同时打开转移路径。简而言之,就是两个连接套接字主动相互连接,完全没有listen的过程。

tcp_state_machine

        下面是一个套接字同时打开的demo

package nonblock;
import java.net.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.nio.*;
import java.io.*;
import java.util.*;


public class SimuOpen {
    private Socket sock1 = null, sock2 = null;
    private int port1 = 50000, port2 = 50001;
    private String host = "localhost";

    public SimuOpen() throws IOException{

    }

    public static void main(String[] args) throws IOException {
        new SimuOpen().work();
    }

    public void work(){
        Worker work1 = new Worker(port1, port2);
        Worker work2 = new Worker(port2, port1);
        work1.start();
        work2.start();

    }



    public class Worker extends Thread{
        private int localport = 0;
        private int remoteport = 0;
        public Worker(int localport, int remoteport){
            this.localport = localport;
            this.remoteport = remoteport;
        }


        private PrintWriter getWriter(Socket socket)throws IOException{
            OutputStream socketOut = socket.getOutputStream();
            return new PrintWriter(socketOut, true);
        }
        private BufferedReader getReader(Socket socket)throws IOException {
            InputStream socketIn = socket.getInputStream();
            return new BufferedReader(new InputStreamReader(socketIn));     
        }

        public void run(){
            while(true){
                try {
                    Socket socket = new Socket();
                    socket.bind(new InetSocketAddress("127.0.0.1",localport));
                    socket.connect(new InetSocketAddress("127.0.0.1",remoteport));
                    BufferedReader br = getReader(socket);
                    PrintWriter pw = getWriter(socket);
                    String msg = "hello world!" + socket.getLocalPort();
                    pw.println(msg);
                    System.out.println(socket.getLocalPort() + ":" + br.readLine());
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    //e.printStackTrace();
                }

            }
        }
    }
}

        输出如下:

  • 50001:hello world!50000
  • 50000:hello world!50001

发表评论