【问题标题】:Getting started with client-server networking [closed]客户端-服务器网络入门[关闭]
【发布时间】:2010-10-28 19:15:08
【问题描述】:

我是一名优秀的程序员,但我的网络经验为零。

基本上,我想进入客户端-服务器网络。例如,我想尝试让服务器进程运行,它允许客户端通过互联网连接并向所有其他连接的客户端发送 ping。然后也许我会尝试开发一个简单的聊天客户端,或者一些简单的多人游戏,然后我会从那里开始。

我非常熟悉但可能有用的语言:Java、C++、C。

我该如何开始?我想提前学习最佳实践,因此您可以推荐好的学习资源(例如书籍、在线资料等)会很棒。

编辑:我是否也应该研究某种虚拟机来模拟各种机器之间的交互?

编辑 2:我提出了 50 个代表的赏金。到目前为止,已经提出了一些很好的答案——不过我正在寻找更详细的答案,所以希望这会鼓励这一点。例如,由具有此类经验的人回答比较不同的学习方法会非常有帮助。谢谢!我还可以就整个 VM 获得一些反馈吗?

【问题讨论】:

  • 只是出于好奇。您是如何设法“非常了解 Java、C 和 C++”但从未涉足网络的?
  • @user384706:通过学习语言的语法、大部分库,并获得大量使用它们的经验。我指定我擅长使用这些语言进行交流,我不需要旨在一起教授编程和网络的初学者教程,或者面向初学者程序员的初学者教程。就像“现在我们将学习 while 循环——然后,我们将继续使用循环一次发送多条数据”:)
  • 根据我的经验,虚拟机并不是必需的...您可以通过在单个操作系统下运行多个进程来模拟多台机器。

标签: java c++ c network-programming


【解决方案1】:

我更喜欢 Java。我将解释 TCP:
基本概念是您必须在机器上运行“服务器”。该服务器接受等待连接的客户端。每个连接都通过一个端口(你知道,我希望...)。
始终使用高于 1024 的端口,因为低于 1025 的端口大部分时间都保留给标准协议(如 HTTP (80)、FTP (21)、Telnet 等)

然而,在 Java 中创建服务器是通过这种方式完成的:

ServerSocket server = new ServerSocket(8888); // 8888 is the port the server will listen on.

如果您想进行研究,“Socket”是您可能正在寻找的词。
并且要将您的客户端连接到服务器,您必须编写以下代码:

Socket connectionToTheServer = new Socket("localhost", 8888); // First param: server-address, Second: the port

但是现在,仍然没有连接。服务器必须接受等待的客户端(正如我在上面注意到的):

Socket connectionToTheClient = server.accept();

完成!您的连接已建立!通信就像 File-IO。您唯一需要记住的是,您必须决定何时刷新缓冲区并真正通过套接字发送数据。
使用 PrintStream 进行文本编写非常方便:

OutputStream out = yourSocketHere.getOutputStream();
PrintStream ps = new PrintStream(out, true); // Second param: auto-flush on write = true
ps.println("Hello, Other side of the connection!");
// Now, you don't have to flush it, because of the auto-flush flag we turned on.

用于文本阅读的 BufferedReader 是不错的(最佳*)选项:

InputStream in = yourSocketHere.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line = br.readLine();
System.out.println(line); // Prints "Hello, Other side of the connection!", in this example (if this would be the other side of the connection.

希望您可以从这些信息开始建立网络!
PS:当然,所有网络代码都必须尝试捕获 IOExceptions。

编辑:我忘了写为什么它并不总是最好的选择。 BufferedReader 使用缓冲区并尽可能多地读取缓冲区。但有时您不希望 BufferedReader 窃取换行符后的字节并将它们放入自己的缓冲区中。
简短的例子:

InputStream in = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
// The other side says hello:
String text = br.readLine();
// For whatever reason, you want to read one single byte from the stream,
// That single byte, just after the newline:
byte b = (byte) in.read();

但是 BufferedReader 在他的缓冲区中已经有了你想要读取的那个字节。因此调用in.read() 将返回阅读器缓冲区中最后一个字节之后的字节。

因此,在这种情况下,最好的解决方案是使用DataInputStream 并以您自己的方式管理它以了解字符串的长度,并仅读取该字节数并将它们转换为字符串。或者:你使用

DataInputStream.readLine()

此方法不使用缓冲区并逐字节读取并检查换行符。所以这个方法不会从底层 InputStream 窃取字节。

【讨论】:

    【解决方案2】:

    Beej 的网络编程指南绝对响亮。在大学用过。

    http://beej.us/guide/bgnet/

    它涵盖了 Sockets API,我记得它使用 C++ 作为代码示例。

    Tannenbaum 的《计算机网络》也是一本极好的读物。

    【讨论】:

    • 事实上我有一些旧的客户端和服务器代码...它来自我的大学时代,不是最好的代码,但也可能会有所帮助!
    • 我简要浏览了这本(网络)书籍,虽然我认可其中的内容,但我认为这不是初学者了解基于 IP 的客户端服务器网络的最佳顺序。恕我直言
    • 提到的 OP 询问的其他一些方面可能很有用(例如一些简单的客户端和服务器程序)我确实在我的回答中提到了这本书作为伴侣。
    • 我们的班级使用这个确切的指南来构建我们的第一个 C 客户端/服务器程序。真的很有用!
    • @cam 我在某处使用结构阅读了 c 语言中 tcp 协议的实现。
    【解决方案3】:
    1. 了解有关网络的基本概念。层、IP 地址、端口、数据包 [特别是 UDP/TCP]

    2. 学习有关 [1] 的编程抽象,例如套接字。

    3. 自己实现“服务器”和“客户端”。

    4. 测试一下。

    5. 在您的计算机上安装 Wireshark,并查找为每种活动类型发送的 IP 地址、数据包类型、端口号等。

    6. 使用 Java/.Net/C++ 的网络 API 构建知识。从头开始构建一切可能是一个非常糟糕的主意。

    Java:http://download.oracle.com/javase/tutorial/networking/index.html

    .Net:http://msdn.microsoft.com/en-us/library/4as0wz7t.aspx

    C++:Richard Stevens 的 Unix 网络编程

    【讨论】:

      【解决方案4】:

      如果您使用的是 C++,我强烈建议您使用 Boost.Asio,这是一个很棒的异步网络库,与直接使用套接字相比,它可以让您更快地实现目标。

      显然,从头开始学习网络知识是一个好主意,但我认为通过一个好的(且易于使用的)库来支持你这样做是非常有益的,这样你也可以获得结果。

      【讨论】:

      • +1 对于 C++ 解决方案,我强烈建议查看 Boost.Asio
      【解决方案5】:

      在我看来,您应该从学习如何使用sockets 开始,比如说,在 C、UNIX 中(任何在线教程都适合,或者使用“man”)。只有在那之后,您才能在谷歌上搜索特定于语言/操作系统的库,然后选择您喜欢的或更适合您需求的任何内容。

      乐: 您始终可以在同一台机器上测试您的应用程序。

      【讨论】:

        【解决方案6】:

        我不能推荐更多book by Richard Stevens

        【讨论】:

          【解决方案7】:

          如果您对 TCP/IP 一无所知,我将从 Douglas E. Comer 的精彩书籍开始:TCP/IP 第 1 卷。

          您不需要阅读所有内容,里面有很多有用的东西。

          一旦您了解了这一点,请查看几个开源网络实现之一,例如 boost asio。恕我直言,这是最容易启动和运行的网络库。一旦这进一步激起了您的兴趣,然后开始研究一些较低级别的套接字细节。顺便说一句,brumScouse 已经提到了 Beej 的指南,这也是一个非常好的资源。

          然后,当您走得更远,并且想要更多时:google C10K! ;)

          【讨论】:

          • 你会说 Beej 的指南属于“低级套接字详细信息”的范围吗?
          • 让我们说,该指南是关于基本套接字 API 的;像 asio 或 ACE 之类的库或任何简单地包装套接字 API 公开的功能的库,并为您提供很好的抽象来使用。所以从这个意义上说,它有点“低级”,但同时它是非常有用的知识,可以让你知道抽象是如何工作的。我首先提到抽象的原因是它隐藏了很多你可能会迷失的实现细节......
          【解决方案8】:

          我主要来自 Linux 网络编程背景。我已经做了一点 Windows 套接字编程,据我所见,Windows 套接字 API 与 POSIX 套接字 API 非常相似,并且在 MSDN 上有一些非常好的信息,用于从 POSIX 移植到 Windows 套接字。

          网络编程在概念上并不难,您需要了解以下几个方面才能有效:首先,您需要对网络有基本的了解。您至少需要了解 TCP 和 IPv4,因为它们很可能是您最终将使用的默认协议。在概念层面上了解一些关于 DNS 和以太网的知识可能也很有用,但一开始并不严格要求。一旦你有基本的背景(阅读一些维基百科文章或网络基本指南可能足以让你开始),你就可以开始查看 POSIX 套接字 API。一旦你掌握了网络基础知识,这些就非常简单了,并且那里有很多教程(Beej 的网络编程指南是由其他人列出的,它非常好,并且手册页实际上也有一些非常有用的示例)。您在这里可能遇到的最大绊脚石是知道网络字节顺序与主机字节顺序需要什么,但根据经验,您写入套接字的任何内容都应首先放入网络字节顺序,以及任何内容您从套接字读取的内容应立即转换为主机字节顺序。

          很多人绊倒的地方在于,仅仅学习 POSIX 套接字 API 并不足以进行有效的网络编程。编写一个简单的 echo 客户端足以让您走得更远,但要超越它,您还需要熟悉其他一些东西。最重要的是使用非阻塞文件描述符、信号、使用 select/epoll/等,以及处理子进程工作流。在高层次上,它在概念上非常简单(create->bind->listen->select->fork->accept),但是如果您不习惯使用文件描述符、select、fork 等,那么这些就是事情你需要跟上进度。

          在我看来,最好的程序之一是 IRC 客户端。它将为您提供所需的所有基础知识(向服务器读取/写入消息、并发连接、处理不同的服务器实现等),该协议非常易于解析,并且有很多服务器可供使用在那里连接。

          【讨论】:

            【解决方案9】:

            您可能想阅读

            Sockets programming in Java: A tutorial

            在 javaworld 上。它解释了基础知识。最初不要试图在低级网络中走得太远。编写一些简单的客户端/服务器代码,看看它是如何工作的。

            【讨论】:

              【解决方案10】:

              这里有一些尚未提及的内容。 Qt

              Qt(c++ 框架)有一个非常好的“网络”类,我用于 TCP 和 UDP 服务器/客户端类型的连接。有几个不同的例子涵盖了两者:

              阻塞连接(使当前线程“等待”返回的连接)

              非阻塞连接(一旦数据可用就会触发回调的连接)

              Check it out 你永远不会回头。他们有很好的记录!!!

              【讨论】:

                【解决方案11】:

                先从基础开始,然后你应该看看真正使用的是什么(在 Java 中):

                1. 对于套接字编程,请使用Apache Mina
                2. 现代客户端服务器应用程序使用RESTJerseyRESTeasy(均符合 JAX-RS)和Restlet(该领域的先驱)。

                【讨论】:

                  【解决方案12】:

                  Stevens 的 UNIX 网络编程 提供了有关使用 BSD 套接字 API(现在是标准套接字 API)以及各种 UNIX 系统如何解释这些 API 中的函数的所有信息。它包含大量代码来演示正在讨论的主题。它也很密集。

                  Beej 的指南是关于如何使用套接字 API 的一个很好的快速总结。它可能是更好的起点之一,只是了解将服务器和客户端放在一起的机制。要了解您为什么要按该顺序使用该数据进行这些函数调用,以及函数调用究竟在做什么,您可以求助于 Stevens。

                  如果您想了解最佳实践,请查看生产代码:Mongrel 2 如何处理网络? lighttpd 怎么样? Varnish?他们为什么要这样处理?

                  您还可以查看您感兴趣的平台的网络堆栈的实现。获取内核源代码,可能是一本讨论内核设计的书,然后深入研究。

                  【讨论】:

                    【解决方案13】:

                    恕我直言,Java 中的套接字编程比 C/C++ 中容易得多。你可以从 Java 教程开始学习:http://download.oracle.com/javase/tutorial/networking/sockets/

                    对于“基本”C/C++ 套接字编程,您可以向"Beej's Guide to Network Programming" 学习。我在大学的时候值得学习:)。然后,您可以了解Windows Socket API 作为下一个起点。

                    要模拟环境,当然你可以使用虚拟机:)

                    【讨论】:

                      猜你喜欢
                      • 2012-04-26
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-03-30
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多