开始使用客户端-服务器网络

2022-01-19 00:00:00 c network-programming c++ java

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

I'm a good programmer, but I have zero network experience.

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

Basically, I'd like to get into client-server networking. For example, I'd like to try getting a server process going which allows clients to connect over the internet and send pings to all of the other connected clients. Then maybe I'll try developing a simple chat client, or some simple multiplayer game and I'll go from there.

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

Languages I know very well that might be useful: Java, C++, C.

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

How do I get started? I want to learn best-practices up front, so good learning resources you can recommend (eg books, online materials, etc) would be great.

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

Should I also look into some kind of VM to emulate various machines interacting with each other?

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

Edit 2: I've put up a 50-rep bounty. Some great answers have been put up so far - I'm looking for more detailed answers though, so hopefully this will encourage that. For example an answer by someone with experience in this type of stuff that compares different learning approaches would be really helpful. Thanks! Also could I get some feedback on the whole VM thing?

推荐答案

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

I prefer Java. I'm going to explain TCP:
The basic concept is that you have to run a "Server" on a machine. That server accepts clients waiting for a connection. Each connection goes over a port (you know, I hope...).
Always use ports above 1024 because ports lower than 1025 are most of the time reserved for standard protocols (like HTTP (80), FTP (21), Telnet, ...)

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

However, creating a Server in Java is done this way:

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

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

"Socket" is the word you are probably looking for if you want to do research.
And to connect your client to a server you have to write this:

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

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

But now, there isn't still a connection. The server has to accept the waiting client (as I noticed here above):

Socket connectionToTheClient = server.accept();

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

Done! Your connection is established! Communicating is just like File-IO. The only thing you have to keep in mind is that you have to decide when you want to flush the buffer and really send the data through the socket.
Using a PrintStream for text-writing is very handy:

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 是不错的(最佳*)选项:

A BufferedReader for text-reading is the good (best*) option:

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.

Hopefully you can start with networking with this information!
PS: Of course, all networking code have to be try-catched for IOExceptions.

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

I forgot to write why it isn't always the best option. A BufferedReader uses a buffer and read as much as it can into the buffer. But sometimes you don't want that the BufferedReader steals the bytes after the newline and put them into his own buffer.
Short example:

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() 将返回阅读器缓冲区中最后一个字节之后的字节.

But the BufferedReader has already that byte, you want to read, in his buffer. So calling in.read() will return the byte following on the last byte in the buffer of the reader.

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

So, in this situation the best solution is to use DataInputStream and manage it your own way to know how long the string will be and read only that number of bytes and convert them into a string. Or: You use

DataInputStream.readLine()

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

This method doesn't use a buffer and reads byte by byte and checks for a newline. So this method doesn't steal the bytes from the underlying InputStream.

相关文章