Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.81/16: Рейтинг темы: голосов - 16, средняя оценка - 4.81
 Аватар для GulgDev
132 / 118 / 29
Регистрация: 09.07.2019
Сообщений: 1,071
.NET 3.x

Сокеты. Непонятные сообщения и странные выводы

05.07.2021, 21:20. Показов 3190. Ответов 15
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!
У меня есть некий удалённый сервер с таким кодом:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
 
namespace SkyJumpServer
{
    enum Message
    {
        JOINED, LOADED, OUTED, MOVED, DATA, VOTE, START
    }
 
    enum GameState
    {
        GAME, LOBBY
    }
 
    class Server
    {
        private static Socket socket;
 
        private static Hashtable clients = new Hashtable();
 
        public static Hashtable clientsData = new Hashtable();
 
        private static GameState gameState;
 
        private static Hashtable votes;
 
        static void Main(string[] args)
        {
            IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 40001);
 
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Bind(ipPoint);
 
            socket.Listen(10);
 
            while (true)
            {
                Socket client = socket.Accept();
 
                String ip = client.RemoteEndPoint.ToString();
 
                SendMessage(Message.JOINED, null, null, ip, "ALL");
 
                clients.Add(ip, client);
 
                new Thread(new ParameterizedThreadStart(ListenClient)).Start(client);
            }
        }
 
        public static void ListenClient(object c)
        {
            Socket client = (Socket) c;
 
            String ip = client.RemoteEndPoint.ToString();
 
            foreach (DictionaryEntry pair in clientsData)
            {
                client.Send(Encoding.UTF8.GetBytes((char[]) pair.Key));
                client.Send(BitConverter.GetBytes((int) pair.Value));
            }
 
            client.Send(Encoding.UTF8.GetBytes("END"));
 
 
            int id = 0;
 
            Message msg = Message.MOVED;
            byte[] lArg = null;
            byte[] rArg = null;
            String recipient = null;
 
            while (!(client.Poll(0, SelectMode.SelectRead) && client.Available == 0))
            {
                id++;
 
                if (id == 4)
                {
                    id = 0;
 
                    Console.WriteLine(msg);
                    Console.WriteLine(lArg);
                    Console.WriteLine(rArg);
                    Console.WriteLine(ip);
                    Console.WriteLine(recipient);
 
                    SendMessage(msg, lArg, rArg, ip, recipient);
                }
 
                byte[] buffer = new byte[client.Available];
 
                client.Receive(buffer);
 
                switch (id) {
                    case 0:
                        msg = (Message) Enum.Parse(typeof(Message), Encoding.UTF8.GetString(buffer));
                        break;
                    case 1:
                        lArg = buffer;
                        break;
                    case 2:
                        rArg = buffer;
                        break;
                    case 3:
                        recipient = Encoding.UTF8.GetString(buffer);
                        break;
                }
            }
 
            clients.Remove(ip);
 
            client.Shutdown(SocketShutdown.Both);
            client.Close();
 
            SendMessage(Message.OUTED, null, null, ip, "ALL");
        }
 
        public static void SendMessage(Message message, byte[] lArg, byte[] rArg, String sender, String recipient)
        {
            lArg = lArg is null ? new byte[0] : lArg;
            rArg = rArg is null ? new byte[0] : rArg;
 
            if (recipient == "SERVER")
                ReceiveMessage(message, lArg, rArg, sender);
            else if (recipient == "ALL")
                foreach (DictionaryEntry pair in clients)
                {
                    Socket client = (Socket)pair.Value;
 
                    client.Send(Encoding.UTF8.GetBytes(message.ToString()));
 
                    client.Send(lArg);
                    client.Send(rArg);
 
                    client.Send(Encoding.UTF8.GetBytes(sender));
                }
            else
            {
                Socket client = (Socket) clients[recipient];
 
                client.Send(Encoding.UTF8.GetBytes(message.ToString()));
                
                client.Send(lArg);
                client.Send(rArg);
                
                client.Send(Encoding.UTF8.GetBytes(sender));
            }
        }
 
        public static void ReceiveMessage(Message message, byte[] lArg, byte[] rArg, string sender)
        {
            switch (message)
            {
                case Message.DATA:
                    clientsData.Add(sender, BitConverter.ToInt32(lArg));
                    break;
                case Message.VOTE:
                    if (gameState == GameState.LOBBY)
                    {
                        int id = BitConverter.ToInt32(lArg);
 
                        if (votes.Contains(id))
                            votes.Add(id, ((int) votes[id]) + 1);
                        else
                            votes.Add(id, 1);
                    }
 
                    break;
            }
        }
 
        public static void GameThread()
        {
            gameState = GameState.LOBBY;
 
            int timeRemaining = 15;
 
            while (timeRemaining > 0) {
                if (clients.Count < 2)
                    continue;
 
                Thread.Sleep(1000);
                timeRemaining--;
            }
 
 
            gameState = GameState.GAME;
 
            DictionaryEntry max;
 
            foreach (DictionaryEntry pair in votes)
                if ((object) max is null || (int) pair.Value > (int) max.Value)
                    max = pair;
 
            votes.Clear();
 
 
            SendMessage(Message.START, BitConverter.GetBytes((int) max.Key), null, "SERVER", "ALL");
        }
    }
}
И Unity клиент:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using UnityEngine;
 
public class RoomConnector : MonoBehaviour
{
    public static RoomConnector instance;
 
    public Transform OtherPlayer;
 
    private static Socket socket;
    private static IPEndPoint ipPoint;
 
    public static Hashtable playersData = new Hashtable();
 
    private int id = 0;
    private Message msg = Message.MOVED;
    private byte[] lArg = null;
    private byte[] rArg = null;
    private String sender = null;
 
    public enum Message
    {
        JOINED, OUTED, MOVED, DATA, VOTE, START
    }
 
    private void Awake()
    {
        ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 40001);
 
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    }
 
    private void Start()
    {
        if (instance == null)
            instance = this;
 
        if (GameObject.Find("Player") != null)
            LoadRoom();
    }
 
    private void OnDestroy()
    {
        socket.Close();
    }
 
    public static void Connect() {
        socket.Connect(ipPoint);
 
        int id = 0;
 
        String ip = "";
        int skin = 0;
 
        while (true)
        {
            if (id == 1)
            {
                id = -1;
 
                playersData[ip] = skin;
            }
 
            if (socket.Available == 0)
                continue;
 
            id++;
 
            byte[] buffer = new byte[socket.Available];
 
            socket.Receive(buffer);
 
            foreach (byte b in buffer)
                Debug.Log(b);
 
            if (Encoding.UTF8.GetString(buffer) == "END")
                break;
 
            switch (id)
            {
                case 0:
                    ip = Encoding.UTF8.GetString(buffer);
                    break;
                case 1:
                    skin = BitConverter.ToInt32(buffer, 0);
                    break;
            }
        }
 
        SendMessage(Message.DATA, BitConverter.GetBytes(PlayerPrefs.GetInt("CurrentSkin")), null, "SERVER");
    }
 
    public static void LoadRoom()
    {
        foreach (DictionaryEntry pair in playersData) {
            String ip = (String) pair.Key;
            int skin = (int) pair.Value;
 
            Transform otherPlayer = Instantiate(instance.OtherPlayer, new Vector3(0f, -3f, -1f), Quaternion.identity);
            otherPlayer.name = ip;
            otherPlayer.GetComponent<SpriteRenderer>().sprite = ChangeSkin.sprites[skin];
        }
    }
 
    void Update()
    {
        if (!socket.Connected)
            return;
 
        GameObject player = GameObject.Find("Player");
 
        if (player != null)
            SendMessage(Message.MOVED, BitConverter.GetBytes(player.transform.position.x), BitConverter.GetBytes(player.transform.position.y), "ALL");
 
        if (id == 3)
        {
            id = -1;
 
            ReceiveMessage(msg, lArg, rArg, sender);
        }
 
        if (socket.Available == 0)
            return;
 
        id++;
 
        byte[] buffer = new byte[socket.Available];
 
        socket.Receive(buffer);
 
        switch (id)
        {
            case 0:
                msg = (Message)Enum.Parse(typeof(Message), Encoding.UTF8.GetString(buffer));
                break;
            case 1:
                lArg = buffer;
                break;
            case 2:
                rArg = buffer;
                break;
            case 3:
                sender = Encoding.UTF8.GetString(buffer);
                break;
        }
    }
 
    [MethodImpl(MethodImplOptions.Synchronized)]
    public static void SendMessage(Message message, byte[] lArg, byte[] rArg, String recipient)
    {
        Debug.Log("START");
        Debug.Log(message);
 
        lArg = lArg is null ? new byte[0] : lArg;
        rArg = rArg is null ? new byte[0] : rArg;
 
        socket.Send(Encoding.UTF8.GetBytes(message.ToString()));
 
        socket.Send(lArg);
        socket.Send(rArg);
 
        Debug.Log(recipient);
 
        socket.Send(Encoding.UTF8.GetBytes(recipient));
 
        Debug.Log("END");
    }
 
    public static void ReceiveMessage(Message message, byte[] lArg, byte[] rArg, String sender)
    {
        switch (message)
        {
            case Message.MOVED:
                GameObject jumper = GameObject.Find(sender);
                jumper.transform.position = new Vector3(BitConverter.ToSingle(lArg, 0), BitConverter.ToSingle(rArg, 0), jumper.transform.position.z);
                break;
            case Message.JOINED:
                break;
            case Message.OUTED:
                playersData.Remove(sender);
                break;
            case Message.DATA:
                playersData.Add(sender, BitConverter.ToInt32(lArg, 0));
                break;
            case Message.START:
                StartStopGame.LoadLevel(BitConverter.ToInt32(lArg, 0));
                break;
        }
    }
}
По выводу клиента понятно, что он вполне нормально отсылает сообщения.
Но по выводу сервера получается чушь. Сообщения смешиваются, данные куда-то пропадают, и появляются. Хотя клиентом было выслано только одно сообщение.
Что происходит? В чём проблема?
Заранее спасибо!
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
05.07.2021, 21:20
Ответы с готовыми решениями:

Странные выводы касательно света
Добрый день, я недавно начал изучать свет как электромагнитную волну и сейчас у меня появился вопрос, ответ на который, возможно, очевиден,...

сокеты непонятные моменты
1. Как выбрать оптимальный размер буфера? Я понимаю что можно поставить и 1 байт данные все равно все будут получены (TCP/IP) , можно...

Странные непонятные названия в библиотеке JSoup
Учусь парсить сайты на java и решил использовать jsoup (он точно лучший для данной задачи?) при попытке импортировать что-либо из jsoup...

15
Эксперт .NET
 Аватар для Usaga
14314 / 9399 / 1355
Регистрация: 21.01.2016
Сообщений: 35,450
06.07.2021, 00:53
Лучший ответ Сообщение было отмечено Hyppoprogramm как решение

Решение

Hyppoprogramm, на это без слёз смотреть сложно. Ужасная каша. Но проблема тут типовая: отсутствие понимания того, что данные по сети передаются более мелкими фрагментами, нежели вы их отправляете. Соотвественно, вы это в коде никак не учитываете. Вот и получаете что попало. Ну и под отладкой вы видимо своё приложение не рассматривали, иначе бы это сразу увидели.

Простой пример:

C#
1
2
3
4
5
6
7
8
9
            byte[] buffer = new byte[socket.Available];
 
            socket.Receive(buffer);
 
            foreach (byte b in buffer)
                Debug.Log(b);
 
            if (Encoding.UTF8.GetString(buffer) == "END")
                break;
Кто вам сказал, что строка END прилетит сразу одним куском, а не двумя? А ведь вся ваша логика на этом и построена. И стоит только первому сообщению фрагментироваться, как вся логика сервера (и клиента) улетает к чертям и такое сообщение просто теряется. Что вы и наблюдаете.

Ваши сообщения должны иметь чётко определённые границы. Ваш код, который принимает сообщения, должен проверять, опираясь на эти границы, что сообщение пришло полностью, прежде чем дальше по условиям его прогонять.

Это что касаемо самого вопроса с корректностью. Другой момент, что в глаза бросается, это ужасная неэффективность передачи данных. У вас на каждое сообщение буферы и строки аллоцируются. А между тем, у вас тут явно игра. Создавая кучи мусора на каждом передаваемом фрейме вы будете забивать кучу на клиенте и на сервере (что хуже), с периодическими фризами на сборку этого мусора силами GC.

Разработка игрового сервера потребует от вас большего понимания языка и платформы, чем вы на данный момент обладаете. Лучше сначала почитайте литературу по этому вопросу. Например это: «Multiplayer Game Programming: Architecting Networked Games (Game Design)».

И научитесь пользоваться отладчиком. Без этого навыка не то, что игры сетевые, а даже консольные утилитки не написать. Или вы собираетесь по каждому чиху на форум бежать?)
2
 Аватар для GulgDev
132 / 118 / 29
Регистрация: 09.07.2019
Сообщений: 1,071
06.07.2021, 08:55  [ТС]
Usaga, если я буду в начале и в конце сообщения отправлять особый байт-"разделитель", то какой лучш6е использовать, чтобы он не встречался нигде в сообщении?
0
Эксперт .NET
 Аватар для Usaga
14314 / 9399 / 1355
Регистрация: 21.01.2016
Сообщений: 35,450
06.07.2021, 08:59
Hyppoprogramm, самый простой способ: отправлять в начале сообщения его размер в байтах. Соответственно, принимающая сторона будет знать сколько байт в буфер нужно "набить" прежде, чем процессить сообщение. Отправитель же всегда знает сколько байт он отправляет.
1
 Аватар для GulgDev
132 / 118 / 29
Регистрация: 09.07.2019
Сообщений: 1,071
06.07.2021, 09:00  [ТС]
Usaga, огромное вам спасибо!
0
Строитель
 Аватар для Nord790
889 / 556 / 194
Регистрация: 01.04.2014
Сообщений: 610
Записей в блоге: 6
06.07.2021, 09:08
Hyppoprogramm, создайте сетевой поток NetworkStream и подключите его к BinaryReader и BinaryWriter.

C#
1
2
3
4
5
            //....
            using NetworkStream nstream = new NetworkStream(tcpclient);
            using BinaryWriter wstream = new BinaryWriter(nstream, Encoding.Default, true);
            //....
            wstream.Write("ваши_данные_в_виде_текста");
C#
1
2
3
4
5
6
             //....
             using NetworkStream nstream = new NetworkStream(tcpclient);
             using BinaryReader rstream = new BinaryReader(nstream, Encoding.Default, true);
             //...
             string message = rstream.ReadString();
             //...
Вложения
Тип файла: zip Project.zip (302.5 Кб, 2 просмотров)
1
 Аватар для GulgDev
132 / 118 / 29
Регистрация: 09.07.2019
Сообщений: 1,071
06.07.2021, 10:03  [ТС]
Usaga, изменил код сервера:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
 
namespace SkyJumpServer
{
    enum Message
    {
        JOINED, LOADED, OUTED, MOVED, DATA, VOTE, START
    }
 
    enum GameState
    {
        GAME, LOBBY
    }
 
    class Server
    {
        private static Socket socket;
 
        private static Hashtable clients = new Hashtable();
 
        public static Hashtable clientsData = new Hashtable();
 
        private static GameState gameState;
 
        private static Hashtable votes;
 
        static void Main(string[] args)
        {
            IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 40001);
 
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Bind(ipPoint);
 
            socket.Listen(10);
 
            while (true)
            {
                Socket client = socket.Accept();
 
                String ip = client.RemoteEndPoint.ToString();
 
                SendMessage(Message.JOINED, null, null, ip, "ALL");
 
                clients.Add(ip, client);
 
                new Thread(new ParameterizedThreadStart(ListenClient)).Start(client);
            }
        }
 
        public static void ListenClient(object c)
        {
            Socket client = (Socket) c;
 
            String ip = client.RemoteEndPoint.ToString();
 
            foreach (DictionaryEntry pair in clientsData)
            {
                byte[] key = Encoding.UTF8.GetBytes((char[])pair.Key);
 
                client.Send(BitConverter.GetBytes(key.Length));
                client.Send(key);
 
                byte[] value = BitConverter.GetBytes((int)pair.Value);
 
                client.Send(BitConverter.GetBytes(value.Length));
                client.Send(value);
            }
 
            client.Send(BitConverter.GetBytes(3));
            client.Send(Encoding.UTF8.GetBytes("END"));
 
 
            int id = 0;
 
            Message msg = Message.MOVED;
            byte[] lArg = null;
            byte[] rArg = null;
            String recipient = null;
 
            while (!(client.Poll(0, SelectMode.SelectRead) && client.Available == 0))
            {
                id++;
 
                if (id == 4)
                {
                    id = 0;
 
                    Console.WriteLine(msg);
                    Console.WriteLine(lArg);
                    Console.WriteLine(rArg);
                    Console.WriteLine(ip);
                    Console.WriteLine(recipient);
 
                    SendMessage(msg, lArg, rArg, ip, recipient);
                }
 
                byte[] buffer = new byte[1];
 
                socket.Receive(buffer);
 
                buffer = new byte[BitConverter.ToInt32(buffer, 0)];
 
                socket.Receive(buffer);
 
                switch (id) {
                    case 0:
                        msg = (Message) Enum.Parse(typeof(Message), Encoding.UTF8.GetString(buffer));
                        break;
                    case 1:
                        lArg = buffer;
                        break;
                    case 2:
                        rArg = buffer;
                        break;
                    case 3:
                        recipient = Encoding.UTF8.GetString(buffer);
                        break;
                }
            }
 
            clients.Remove(ip);
 
            client.Shutdown(SocketShutdown.Both);
            client.Close();
 
            SendMessage(Message.OUTED, null, null, ip, "ALL");
        }
 
        public static void SendMessage(Message message, byte[] lArg, byte[] rArg, String sender, String recipient)
        {
            lArg = lArg is null ? new byte[0] : lArg;
            rArg = rArg is null ? new byte[0] : rArg;
 
            byte[] msg = Encoding.UTF8.GetBytes(message.ToString());
 
            byte[] rec = Encoding.UTF8.GetBytes(recipient);
 
            if (recipient == "SERVER")
                ReceiveMessage(message, lArg, rArg, sender);
            else if (recipient == "ALL")
                foreach (DictionaryEntry pair in clients)
                {
                    Socket client = (Socket)pair.Value;
 
                    socket.Send(BitConverter.GetBytes(msg.Length));
                    socket.Send(msg);
 
                    socket.Send(BitConverter.GetBytes(lArg.Length));
                    socket.Send(lArg);
 
                    socket.Send(BitConverter.GetBytes(rArg.Length));
                    socket.Send(rArg);
 
                    socket.Send(BitConverter.GetBytes(rec.Length));
                    socket.Send(rec);
                }
            else
            {
                Socket client = (Socket) clients[recipient];
 
                socket.Send(BitConverter.GetBytes(msg.Length));
                socket.Send(msg);
 
                socket.Send(BitConverter.GetBytes(lArg.Length));
                socket.Send(lArg);
 
                socket.Send(BitConverter.GetBytes(rArg.Length));
                socket.Send(rArg);
 
                socket.Send(BitConverter.GetBytes(rec.Length));
                socket.Send(rec);
            }
        }
 
        public static void ReceiveMessage(Message message, byte[] lArg, byte[] rArg, string sender)
        {
            switch (message)
            {
                case Message.DATA:
                    clientsData.Add(sender, BitConverter.ToInt32(lArg));
                    break;
                case Message.VOTE:
                    if (gameState == GameState.LOBBY)
                    {
                        int id = BitConverter.ToInt32(lArg);
 
                        if (votes.Contains(id))
                            votes.Add(id, ((int) votes[id]) + 1);
                        else
                            votes.Add(id, 1);
                    }
 
                    break;
            }
        }
 
        public static void GameThread()
        {
            gameState = GameState.LOBBY;
 
            int timeRemaining = 15;
 
            while (timeRemaining > 0) {
                if (clients.Count < 2)
                    continue;
 
                Thread.Sleep(1000);
                timeRemaining--;
            }
 
 
            gameState = GameState.GAME;
 
            DictionaryEntry max;
 
            foreach (DictionaryEntry pair in votes)
                if ((object) max is null || (int) pair.Value > (int) max.Value)
                    max = pair;
 
            votes.Clear();
 
 
            SendMessage(Message.START, BitConverter.GetBytes((int) max.Key), null, "SERVER", "ALL");
        }
    }
}
И клиента:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using UnityEngine;
 
public class RoomConnector : MonoBehaviour
{
    public static RoomConnector instance;
 
    public Transform OtherPlayer;
 
    private static Socket socket;
    private static IPEndPoint ipPoint;
 
    public static Hashtable playersData = new Hashtable();
 
    private int id = 0;
    private Message msg = Message.MOVED;
    private byte[] lArg = null;
    private byte[] rArg = null;
    private String sender = null;
 
    public enum Message
    {
        JOINED, OUTED, MOVED, DATA, VOTE, START
    }
 
    private void Awake()
    {
        ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 40001);
 
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    }
 
    private void Start()
    {
        if (instance == null)
            instance = this;
 
        if (GameObject.Find("Player") != null)
            LoadRoom();
    }
 
    private void OnDestroy()
    {
        socket.Close();
    }
 
    public static void Connect() {
        socket.Connect(ipPoint);
 
        int id = 0;
 
        String ip = "";
        int skin = 0;
 
        while (true)
        {
            if (id == 1)
            {
                id = -1;
 
                playersData[ip] = skin;
            }
 
            if (socket.Available == 0)
                continue;
 
            id++;
 
            byte[] buffer = new byte[1];
 
            socket.Receive(buffer);
 
            buffer = new byte[BitConverter.ToInt32(buffer, 0)];
 
            socket.Receive(buffer);
 
            if (Encoding.UTF8.GetString(buffer) == "END")
                break;
 
            switch (id)
            {
                case 0:
                    ip = Encoding.UTF8.GetString(buffer);
                    break;
                case 1:
                    skin = BitConverter.ToInt32(buffer, 0);
                    break;
            }
        }
 
        SendMessage(Message.DATA, BitConverter.GetBytes(PlayerPrefs.GetInt("CurrentSkin")), null, "SERVER");
    }
 
    public static void LoadRoom()
    {
        foreach (DictionaryEntry pair in playersData) {
            String ip = (String) pair.Key;
            int skin = (int) pair.Value;
 
            Transform otherPlayer = Instantiate(instance.OtherPlayer, new Vector3(0f, -3f, -1f), Quaternion.identity);
            otherPlayer.name = ip;
            otherPlayer.GetComponent<SpriteRenderer>().sprite = ChangeSkin.sprites[skin];
        }
    }
 
    void Update()
    {
        if (!socket.Connected)
            return;
 
        GameObject player = GameObject.Find("Player");
 
        if (player != null)
            SendMessage(Message.MOVED, BitConverter.GetBytes(player.transform.position.x), BitConverter.GetBytes(player.transform.position.y), "ALL");
 
        if (id == 3)
        {
            id = -1;
 
            ReceiveMessage(msg, lArg, rArg, sender);
        }
 
        if (socket.Available == 0)
            return;
 
        id++;
 
        byte[] buffer = new byte[1];
 
        socket.Receive(buffer);
 
        buffer = new byte[BitConverter.ToInt32(buffer, 0)];
 
        socket.Receive(buffer);
 
        switch (id)
        {
            case 0:
                msg = (Message)Enum.Parse(typeof(Message), Encoding.UTF8.GetString(buffer));
                break;
            case 1:
                lArg = buffer;
                break;
            case 2:
                rArg = buffer;
                break;
            case 3:
                sender = Encoding.UTF8.GetString(buffer);
                break;
        }
    }
 
    [MethodImpl(MethodImplOptions.Synchronized)]
    public static void SendMessage(Message message, byte[] lArg, byte[] rArg, String recipient)
    {
        Debug.Log("START");
        Debug.Log(message);
 
        lArg = lArg is null ? new byte[0] : lArg;
        rArg = rArg is null ? new byte[0] : rArg;
 
        byte[] msg = Encoding.UTF8.GetBytes(message.ToString());
 
        byte[] rec = Encoding.UTF8.GetBytes(recipient);
 
        socket.Send(BitConverter.GetBytes(msg.Length));
        socket.Send(msg);
 
        socket.Send(BitConverter.GetBytes(lArg.Length));
        socket.Send(lArg);
 
        socket.Send(BitConverter.GetBytes(rArg.Length));
        socket.Send(rArg);
 
        socket.Send(BitConverter.GetBytes(rec.Length));
        socket.Send(rec);
 
        Debug.Log("END");
    }
 
    public static void ReceiveMessage(Message message, byte[] lArg, byte[] rArg, String sender)
    {
        switch (message)
        {
            case Message.MOVED:
                GameObject jumper = GameObject.Find(sender);
                jumper.transform.position = new Vector3(BitConverter.ToSingle(lArg, 0), BitConverter.ToSingle(rArg, 0), jumper.transform.position.z);
                break;
            case Message.JOINED:
                break;
            case Message.OUTED:
                playersData.Remove(sender);
                break;
            case Message.DATA:
                playersData.Add(sender, BitConverter.ToInt32(lArg, 0));
                break;
            case Message.START:
                StartStopGame.LoadLevel(BitConverter.ToInt32(lArg, 0));
                break;
        }
    }
}
Теперь на строке 104 выдаёт ошибку:
Code
1
Запрос на отправку или получение данных  (when sending on a datagram socket using a sendto call) no address was supplied.
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,575
06.07.2021, 10:14
Лучший ответ Сообщение было отмечено Hyppoprogramm как решение

Решение

C#
1
2
3
                socket.Receive(buffer);
 
                socket.Receive(buffer);
тут должен быть не socket, а client

А вообще по прежнему жуткий говнокод. Сделайте лучше как выше предложили с использованием BinaryReader/BinaryWriter и тогда все эти ваши буферы, битконвертеры и т.д. будут не нужны...
1
 Аватар для GulgDev
132 / 118 / 29
Регистрация: 09.07.2019
Сообщений: 1,071
06.07.2021, 10:15  [ТС]
Someone007, спасибо, накопировал и не заметил. На BinaryReader/BinaryWriter переписывать не хочу - долго. Знаю, что сглупил.
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,575
06.07.2021, 10:18
Цитата Сообщение от Hyppoprogramm Посмотреть сообщение
На BinaryReader/BinaryWriter переписывать не хочу - долго.
Не долго... И кода меньше будет...
1
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
06.07.2021, 10:24

Не по теме:

Цитата Сообщение от Nord790 Посмотреть сообщение
ваши_данные_в_виде_текста
по ходу то что все примеры по работе с tcp сводятся к отправке текста, в конечном счеты сыграло злую шутку...



Цитата Сообщение от Usaga Посмотреть сообщение
самый простой способ: отправлять в начале сообщения его размер в байтах.
Подключить какой-нибудь форматер умеющий в binary, json или xml сериализацию и скормить ему Stream будет повеселей.
0
 Аватар для GulgDev
132 / 118 / 29
Регистрация: 09.07.2019
Сообщений: 1,071
06.07.2021, 18:19  [ТС]
Someone007, теперь выдаёт ошибку
Code
1
ArgumentException: Destination array is not long enough to copy all the items in the collection. Check array index and length.
Добавлено через 21 секунду
(Сервер, 137 строка)

Добавлено через 1 час 0 минут
Someone007, честно говоря понимаю, что морок меньше будет с BinaryWriter/BinaryReader, но не понимаю, как это использовать в моём коде. Подскажите, пожалуйста. Или посоветуйте ресурс.
0
 Аватар для Рядовой
1524 / 914 / 329
Регистрация: 17.05.2015
Сообщений: 3,438
06.07.2021, 22:12
Hyppoprogramm, лучше всего использовать готовую библиотеку, например signalR.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
07.07.2021, 01:58
gRPC тоже хороша
0
 Аватар для GulgDev
132 / 118 / 29
Регистрация: 09.07.2019
Сообщений: 1,071
07.07.2021, 09:27  [ТС]
Рядовой, kolorotur, BinaryWriter/BinaryReader думаю подойдёт больше.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
07.07.2021, 09:40
Hyppoprogramm, BinaryReader/Writer подходит для чтения/записи простых типов или "сырых" данных в виде массивов байт, а код автора уж больно похож на попытку реализовать обмен сообщениями в реальном времени, т.е. на уровень выше.
Для обмена сообщениями есть отлично зарекомендовавшие себя в реальных проектах решения.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
07.07.2021, 09:40
Помогаю со студенческими работами здесь

Непонятные сообщения в Eclipse IDE
Всем здравствуйте. Пытаюсь изучить Java по книге Файн Я. - Программирование на Java для детей, родителей, дедушек и бабушек - 2011....

Сервер выдаёт непонятные сообщения
Здравствуйте, подскажите, пожалуйста, почему запущенный локальный сервер может периодически (примерно раз в минуту) выдавать сообщение...

Сокеты. Вывести отправляемые и принимаемые сообщения
Создал приложение для проверки доступности порта на узле, нужно дополнить функционал, чтобы получилось клиентское приложение, ...

Сокеты, ошибка при отправлении сообщения
Есть клиент-серверное приложение. По поводу клиентской части ничего не могу сказать, так как нет к ней доступа. Ошибка заключается при...

Передача сообщения от клиента к серверу, сокеты
Хочу передать сообщение от клиента к серверу и вывести это сообщение. Как это сделать? сервер #ifndef UNICODE #define UNICODE ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Новые блоги и статьи
Очистка реквизитов документа при копировании
Maks 09.04.2026
Алгоритм из решения ниже применим как для типовых, так и для нетиповых документов на самых различных конфигурациях. Задача: при копировании документа очищать определенные реквизиты и табличную. . .
модель ЗдравоСохранения 8. Подготовка к разному выполнению заданий
anaschu 08.04.2026
https:/ / github. com/ shumilovas/ med2. git main ветка * содержимое блока дэлэй из старой модели теперь внутри зайца новой модели 8ATzM_2aurI
Блокировка документа от изменений, если он открыт у другого пользователя
Maks 08.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в конфигурации КА2. Задача: запретить редактирование документа, если он открыт у другого пользователя. / / . . .
Система безопасности+живучести для сервера-слоя интернета (сети). Двойная привязка.
Hrethgir 08.04.2026
Далее были размышления о системе безопасности. Сообщения с наклонным текстом - мои. А как нам будет можно проверить, что ссылка наша, а не подделана хулиганами, которая выбросит на другую ветку и. . .
Модель ЗдрввоСохранения 7: больше работников, больше ресурсов.
anaschu 08.04.2026
работников и заданий может быть сколько угодно, но настроено всё так, что используется пока что только 20% kYBz3eJf3jQ
Дальние перспективы сервера - слоя сети с космологическим дизайном интефейса карты и логики.
Hrethgir 07.04.2026
Дальнейшее ближайшее планирование вывело к размышлениям над дальними перспективами. И вот тут может быть даже будут нужны оценки специалистов, так как в дальних перспективах всё может очень сильно. . .
Горе от ума
kumehtar 07.04.2026
Эта мне ментальная установка, что вот прямо сейчас, мол, мне для полного счастья не хватает (нужное вписать), и когда я этого достигну - тогда и полный кайф. Одна из самых сильных ловушек на пути. . . .
Использование значений реквизитов справочника в документе, с определенными условиями и правами
Maks 07.04.2026
1. Контроль срока действия договора Алгоритм из решения ниже реализован на примере нетипового документа "ЗаявкаНаРаботу", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru