套接字编程中的基本控制流程

Basic flow of control in Socket Programming

我在 Java 中使用套接字编程编写了一个简单的客户端服务器程序,但我无法理解该程序的基本控制流程。

客户端文件

public static void main(String args[]) throws UnknownHostException, IOException, InterruptedException{
      1. System.out.println("CLIENT:  "+"client main method started");

      2. Socket s=new Socket("localhost",23456);

      3. BufferedWriter br=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

      4. br.write("CLIENT:  "+"here comes the client message");

      5.br.flush();

    }



服务器文件

public static void main(String args[]) throws IOException, InterruptedException{

        11. System.out.println("Server is started");

        12. ServerSocket ser=new ServerSocket(23456);

        13. Socket s=ser.accept();

        14. System.out.println("SERVER: "+"Server is now accepting connections");

        15. System.out.println("SERVER: "+"client connected");

        16. BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));

        17. String str=br.readLine();

        18. System.out.println("SERVER: "+"Client Message: "+str);
    }


如果有人能借助行号(即逐条语句)向我解释程序流程,那将非常有帮助。
P.S - 服务器文件的行号以 11 开头,只是为了方便起见。
谢谢。

正如 Jose Luis 所说,服务器必须具有正确的配置才能连接到客户端,

11 --> 12 --> 13 --> 14 then 1--> 2--> 3--> 4--> 5

此后服务器和客户端可以交换信息

看看这张描述性图片:

客户端非常简单。它打开一个到服务器的套接字并写入它。

服务器比较复杂。第 12 行在指定端口上创建套接字。第 13 行将等待客户端连接到该端口并发送消息。然后第 16-18 行相当简单。他们从套接字(由客户端放在那里)读取消息并将其打印出来。

据我了解,任何 server/client 应用程序的常规流程是:

  1. 服务器套接字已建立。

  2. 服务器正在端口 23456 上侦听传入连接(阻塞等待)。一旦解除阻塞,解除阻塞的连接请求将存储在套接字中。

  3. 客户端通过Socket向服务器发送消息,服务器解除阻塞时立即存储该消息。

  4. 服务器因为收到消息而唤醒(解除阻塞),并建立Socket连接。

  5. 服务器从客户端读取消息。 (如果您跳过此步骤,客户通常会感到困惑)。这是通过接受的套接字完成的。

  6. 服务器生成对客户端的响应并通过接受的套接字的写入流发送。

  7. 服务器关闭(接受的套接字的)输出流以指示通信结束。 (这是必需的)。

相关示例:

这是一个相对简单的(不是真的,但我尽量明确)自包含的 Web 服务器,它在端口 80 上侦听。一旦你 运行 它,转到 http://127.0.0.1:80查看默认页面。在此程序中,客户端是您的 Web 浏览器(或任何其他试图在本地主机 80 上侦听的程序)

import java.net.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;
import javax.swing.*;
import java.awt.*;
import jserv.*;

public class JavaServer
{
    public static void main(String[] args) 
        throws Exception
    {
        ServerSocket server = null;
        Socket conn = null;
        BufferedReader in = null;
        PrintWriter out = null;
        String msg = null;
        ArrayList<String> tcp_get = null;

        System.out.println("server> Starting!");

        server = new ServerSocket(80);         

        while (true) {
            System.out.println("server> Waiting on a connection.");

            conn = server.accept();

            System.out.println("server> Obtaining io handles.");

            out = new PrintWriter(conn.getOutputStream(), true);           
            in = new BufferedReader (
                new InputStreamReader (
                    conn.getInputStream()
                )
            );

            System.out.println("server> We get signal.");

            while ((msg = in.readLine()) != null) {
                System.out.println("        " + msg);

                /* done if empty line or null. */
                if (msg.isEmpty()) {
                    System.out.println("-- all client info is read --");
                    break;
                }

                /* additional protocol handling. */
                if (msg.startsWith("GET")) {
                    tcp_get = get_decode(msg);
                }
            }

            System.out.println("server> sending a message to client.");        

            /* send the HTML data. acknowledge? */
            /* header */
            out.write("HTTP/1.0 200 OK\r\n");
            out.write("Content-Type: text/html\r\n");
            out.write("\r\n");

            /* response division. */
            System.out.println("tcp_get empty: " + tcp_get.isEmpty());
            if (!tcp_get.isEmpty()) {
                String page = tcp_get.get(0);

                /* we have a page request. */
                if (isValidPage(page)) {
                    File f = new File(page);

                    try {
                        Scanner br = new Scanner(new FileInputStream(f));
                        String s;

                        while ((s = br.nextLine()) != null) {
                            out.write(s + "\r\n");
                        }

                        br.close();

                        out.write("\r\n");
                        System.out.println("server> closing stream.");        
                    } catch (FileNotFoundException e) {                
                        out.write("<p>ERROR 404!</p>\r\n");
                        out.write("\r\n");
                        System.out.println("sent default message.");
                    } catch (Exception e) {}
                }
                /* once the stream is closed, the client will receive the data."); */
            } else {
                out.write("<p>Welcome to the default page!</p>\r\n");
                out.write("\r\n");
            }
            out.close();

            System.out.println("server> end of communication.");        
        }
    }

    private static boolean isValidPage(String page)
    {
        Pattern pat = Pattern.compile("\w+\.html");
        Matcher mat = pat.matcher(page);

        return mat.matches();
    }

    private static ArrayList<String> get_decode(String get) 
    {
        ArrayList<String> tmp = new ArrayList<String>();
        Pattern pat;
        Matcher mat;
        String page;

        String page_pattern = "\w+\.html";
        String arg_pattern = "\w+=\w+";
        String gt = get.replaceFirst(page_pattern, "");       

        /* obtain the page name. */        
        pat = Pattern.compile(page_pattern);
        mat = pat.matcher(get);

        if (!mat.find()) {
            System.out.println("decode> GET invalid.");    
            return tmp;
        } else {
            page = mat.group();
            System.out.println("GET requests " + page);            
            tmp.add(page);
        }

        /* strip name from get. */
        gt = get.replaceFirst(page_pattern, "");        

        /* obtain the arguments. */
        pat = Pattern.compile(arg_pattern);
        mat = pat.matcher(gt);

        while (mat.find()) {
            System.out.println("argument: " + mat.group());
            tmp.add(mat.group());
        }        

        return tmp;
    }
}

针对你的实际代码,请结合我列出的7点回头看这段代码。

import java.net.*;
import java.io.*;

class Client {
    public static void main(String args[]) throws Exception {        
        System.out.println("client> started.");
        Socket s = new Socket("localhost", 23456);
        BufferedWriter br = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        // all messages must end with two linefeeds.
        br.write("hello, world!\n\n");
        // two linefeeds with no messages indicates end.
        br.write("\n\n");

        // see part 7. closing the stream flushes the output.
        br.close();
    }
}

class Server {
    public static void main(String args[]) throws Exception {
        ServerSocket ser = null;
        Socket s = null;
        BufferedReader br = null;
        String str = null;

        System.out.println("server> started");
        ser = new ServerSocket(23456);
        s = ser.accept();
        System.out.println("server> we get signal.");                
        br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        while ((str = br.readLine()) != null) {
            if (str.isEmpty()) {
                System.out.println("server> everything is received.");
                break;
            }
            System.out.println("server> got message: " + str);
        }
        System.out.println("server> done.");
    }
}