简体   繁体   English

Java套接字编程

[英]Java socket programming

Leading on from my previous questions I am going to try and clarify one of the problems I am facing. 在我之前提出的问题中,我将尝试澄清我面临的一个问题。

I am trying to create a multiplayer version of PacMan. 我正在尝试创建一个多人版PacMan。

A simple overview of how i've made my application is that I have a server which has a ServerSocket which is constantly listening on a specific port. 我如何制作应用程序的简单概述是我有一台服务器,它有一个持续监听特定端口的ServerSocket。 Once a client connects it creates a thread in which all the transferring of data takes place. 一旦客户端连接,它就会创建一个线程,在该线程中进行所有数据传输。 It first listens for the Direction in which the client wants to move and then sends the updates back to the client. 它首先侦听客户端想要移动的Direction,然后将更新发送回客户端。 On the client side it's the reverse of this sending the direction and then waiting for the update to be received. 在客户端,它与发送方向相反,然后等待接收更新。 This is done using ObjectOutput/Input Streams. 这是使用ObjectOutput / Input Streams完成的。 There is also a game class which has all the game logic and this has the game loop which each looping calls each of the connected players serverThread.exchangeDatas() method. 还有一个游戏类,它具有所有游戏逻辑,并且具有游戏循环,每个循环调用每个连接的玩家serverThread.exchangeDatas()方法。

My game works ok with one client connected but as soon as another client joins (locally is all that i've tested, but this should work right?) It crashed my game in the Server thread producing the following error java.io.StreamCorruptedException: invalid type code: 00. 我的游戏工作正常,一个客户端连接但是一旦另一个客户端加入(本地就是我测试的所有,但这应该正常工作?)它在服务器线程中崩溃我的游戏产生以下错误java.io.StreamCorruptedException:无效的类型代码:00。

Is the code that trips this exception 是否会导致此异常的代码

        Object o = in.readObject();
        if (o instanceof Direction)
        {
            // Get new location
            player.setDirection((Direction) o);
        //System.out.println("Got: " + (Direction)o + " new location: " + player.getNextLocation());
        }

        // Send gameState

        //System.out.println("Sending data");
        Data data = new Data(game.getGameState(), game.getScared(), game.getScareLeft(), player.getLives(), player.getScore());
        out.flush();
        out.writeObject(data);
        out.flush();
        out.reset();

Server code 服务器代码

ServerThread code (the one that crashes in the exchangeData method ServerThread代码(在exchangeData方法中崩溃的代码)

Client Controller code Client Controller代码

Game loop code - line 42 is what calls the exchange data method 游戏循环代码 - 第42行是调用交换数据的方法

Any help would be amazing with these. 任何帮助都会令人惊叹。

http://www.mediafire.com/download.php?nwwqmzywfom http://www.mediafire.com/download.php?nwwqmzywfom

here's a download to both the client and the server (they are netbeans projects) 这里是客户端和服务器的下载(它们是netbeans项目)

Sorry for my messy code =[ 对不起,我的杂乱代码= [

This is hard to debug without the rest of the code, so I'm going to post my first through and play around a little. 如果没有剩下的代码,这很难调试,所以我要发布我的第一个并玩一下。 Why are you calling .reset() on your streams? 你为什么要在你的溪流上调用.reset()? That would move the read position in the stream back to the start, which isn't what you want I would think (never used ObjectInputStream). 这会将流中的读取位置移回到开始,这不是我想要的(从未使用过ObjectInputStream)。


OK, I took your code and hacked up some little stuff so it would compile, and it worked for me with the .reset(). 好的,我拿了你的代码并且修改了一些小东西,所以它会编译,并且它对我有效.reset()。 It looks like what you were doing there is right. 看起来你在那里做的是对的。

I don't think I can help more without the rest of the code. 如果没有剩下的代码,我认为我无法提供更多帮助。 Sorry. 抱歉。

PS: I assume that you have things Serializable, implementing Runnable, etc which the code you posted didn't have. PS:我假设你有Seri​​alizable,实现Runnable等,你发布的代码没有。 But if you didn't have those things setup, then your code wouldn't compile in the first place. 但是如果你没有设置那些东西,那么你的代码就不会在第一时间编译。


After messing around with your code for 45 minutes, I can't get the error to happen. 在搞乱你的代码45分钟后,我无法得到错误。 I had to hack a few things here and there to make it run (since it was missing a class or two and some of the code above) but I don't think I changed it (much). 我不得不在这里和那里做一些事情来使它运行(因为它缺少一两个类和上面的一些代码)但我不认为我改变它(很多)。 I'm not sure my changes would effect anything, it's a little hard to know. 我不确定我的改变会对任何事情产生影响,这有点难以理解。

I have two guesses as to what's happening. 我有两个猜测发生了什么。 The first is going to be the .reset() thing again. 第一个是再次成为.reset()的东西。 If you haven't commented that out and see if it makes any difference. 如果你没有评论出来,看看它是否有任何区别。

So with that ignored, I'm going to take a different stab at what's going on here. 因此,如果被忽略,我将采取不同的方式来解决这里发生的事情。

java.io.StreamCorruptedException: invalid type code: 00

I'm going to guess that the 00 might be a hint. 我猜测00可能是一个提示。 My understanding is that there should be a signature byte being sent over (as proof that the object is what you say it is, so Strings don't get interpreted as doubles or PacManGameUIs) and obviously Java is unhappy because it's wrong. 我的理解是应该发送一个签名字节(作为对象就是你所说的那样的证明,所以字符串不会被解释为双打或PacManGameUI),显然Java不高兴,因为它是错误的。

But why 00? 但为什么00? That's an interesting value. 这是一个有趣的价值。 My guess (and this is a big guess) is that is the first byte of an integer (which is 4 bytes when sent with ObjectOutputStream.writeInt()). 我的猜测(这是一个很大的猜测)是这是整数的第一个字节(与ObjectOutputStream.writeInt()一起发送时是4个字节)。 Perhaps you have an integer being sent that isn't being read before you call .readObject on the input stream? 也许你在输入流上调用.readObject之前有一个未被读取的整数? I'm not sure if that would cause the error, but it would be my best guess. 我不确定这是否会导致错误,但这是我最好的猜测。

In a situation like this, there are two things to do. 在这种情况下,有两件事要做。 The first is to cut things down. 首先是减少事情。 Make two little class files that do nothing but start threads that communicate with each other in a cut down manner (without all the game management stuff) but using the same flow and logic. 制作两个小类文件,除了启动线程以减少的方式相互通信(没有所有游戏管理的东西),但使用相同的流程和逻辑。 See if you can re-create the error there. 看看你是否可以在那里重新创建错误。

The other way (and this will be more instructive if you are daring) is to listen in on the conversation between the two program halves using something like WireShark or tcpdump . 另一种方式(如果你大胆的话,这将更有启发性)是使用WireSharktcpdump之类的东西来监听两个程序之间的对话。 This will let you see the raw bytes you are sending across. 这将让您看到您发送的原始字节。 While this can be confusing and hard to interpret, it should make figuring out if you are sending the wrong object easy. 虽然这可能令人困惑且难以解释,但它应该弄清楚你是否容易发送错误的对象。 Sending an int will probably be around 4 bytes, but sending a large structure would take more. 发送一个int可能大约是4个字节,但发送一个大型结构需要更多。 Through experimentation you should be able to figure it out. 通过实验,你应该能够弄明白。 It's a pain, but it will let you know exactly what is being sent. 这很痛苦,但它会让你确切知道发送的什么。

It may be hard to snoop on the loopback interface (when a computer talks to it's self), at least on Windows with WireShark (I don't remember it being that easy), so it's often easiest to do this with two computers (one as server, one as client) so you can easily peek into the packets. 可能很难窥探环回接口(当计算机与其自身对话时),至少在使用WireShark的Windows上(我不记得那么容易),因此通常最容易使用两台计算机(一台计算机)作为服务器,一个作为客户端),因此您可以轻松查看数据包。

Sorry again that I can't be more helpful. 再次抱歉,我无法提供更多帮助。

Multithreading needs synchronisation. 多线程需要同步。 Are you using a synced stream (or syncing the access to the stream yourself)? 您是使用同步流(还是自己同步对流的访问)?

Update: The code sample given may very well be called from multiple threads. 更新:可以从多个线程调用给出的代码示例。 If multiple threads access the same stream, errors like the ones you are experiencing may very well occur. 如果多个线程访问同一个流,则可能会出现与您遇到的错误类似的错误。

I suggest having a look at http://java.sun.com/docs/books/tutorial/essential/concurrency/sync.html . 我建议看看http://java.sun.com/docs/books/tutorial/essential/concurrency/sync.html

By marking a method/class synchronized, the runtime will make sure that this method/class will be active in no more than 1 thread at the same time. 通过标记方法/类同步,运行时将确保此方法/类同时在不超过1个线程中处于活动状态。 This is actually a vast and difficult topic, so take some time to learn the basics and make sure you understand the basic problem. 这实际上是一个庞大而困难的话题,所以花点时间学习基础知识并确保你理解基本问题。 :) :)

Maybe a bit off topic but javagaming.org has a section for 'OnLine Game Development & Networking'. 也许有点偏离主题,但javagaming.org有一个“OnLine游戏开发和网络”部分。 You might want to check that as well. 您可能也想检查一下。

Can I just ask what you expect to happen if it were possible for a second client to join? 如果第二个客户可以加入,我可以问一下您预期会发生什么吗? You're not storing the reference of that Thread object, when another iteration occurs the object no longer has a reference therefore the JRE would destroy the object, would it not? 你没有存储那个Thread对象的引用,当另一个迭代发生时,对象不再有引用,因此JRE会破坏对象,不是吗?

while (true)
{
    System.out.println("Waiting for conneciton on port " + port);
    Socket client = listener.accept();
    System.out.println("Accepted a connection from: " + client.getInetAddress());
    Thread t = new Thread(new PacManServerThread(client, game));
    t.start();
}

Surely you need to to do something like 当然你需要做类似的事情

myGenericArray.add(t);

at the end of your loop otherwise once the object loses scope in the loop it would be destroyed? 在循环结束时否则一旦对象在循环中失去范围,它将被销毁?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM