套接字编程中的基本控制流程
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 应用程序的常规流程是:
服务器套接字已建立。
服务器正在端口 23456 上侦听传入连接(阻塞等待)。一旦解除阻塞,解除阻塞的连接请求将存储在套接字中。
客户端通过Socket向服务器发送消息,服务器解除阻塞时立即存储该消息。
服务器因为收到消息而唤醒(解除阻塞),并建立Socket连接。
服务器从客户端读取消息。 (如果您跳过此步骤,客户通常会感到困惑)。这是通过接受的套接字完成的。
服务器生成对客户端的响应并通过接受的套接字的写入流发送。
服务器关闭(接受的套接字的)输出流以指示通信结束。 (这是必需的)。
相关示例:
这是一个相对简单的(不是真的,但我尽量明确)自包含的 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.");
}
}
我在 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 应用程序的常规流程是:
服务器套接字已建立。
服务器正在端口 23456 上侦听传入连接(阻塞等待)。一旦解除阻塞,解除阻塞的连接请求将存储在套接字中。
客户端通过Socket向服务器发送消息,服务器解除阻塞时立即存储该消息。
服务器因为收到消息而唤醒(解除阻塞),并建立Socket连接。
服务器从客户端读取消息。 (如果您跳过此步骤,客户通常会感到困惑)。这是通过接受的套接字完成的。
服务器生成对客户端的响应并通过接受的套接字的写入流发送。
服务器关闭(接受的套接字的)输出流以指示通信结束。 (这是必需的)。
相关示例:
这是一个相对简单的(不是真的,但我尽量明确)自包含的 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.");
}
}