Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.72/18: Рейтинг темы: голосов - 18, средняя оценка - 4.72
12 / 12 / 7
Регистрация: 09.10.2013
Сообщений: 222

Реализация асинхронного клиента и сервера

17.08.2015, 09:58. Показов 3739. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Пытался сделать следующее:

Клиент подключается к серверу и все время прослушивает его до тех пор, пока в форме не введут сообщение и не нажмут - отправить. После отправки клиент в тот же миг начинает снова слушать сервер. Что-то похожее и с сервером. Он все время отправляет данные клиенту до тех пор, пока не получит данные, которые обработает и продолжит отправлять свои прежние сообещния клиенту.

Теоретические вопросы:
1) Правильно ли это? Постоянно слушать/ожидать пакеты.
2) Можно ли каким-то образом и принимать данные и отправлять одновременно (может в нескольких потоках)?
3) Стоит ли каждого подключенного клиента кидать в отдельный поток? (Если кол-во подключений может дойти до 1-5 тыс.)
4) Можно ли как-то прослеживать кол-во отправленных пакетов в секунду? Можно ли ограничивать?
5) Данный вопрос исходит из 2 и 3. 5 тыс. подключений + каждое подключение слушает и отправляет в своем потоке. 10-15 тыс. потоков - это огромное кол-во? Какие последствия?
6) Сколько, вообще, потоков можно открывать? (В норме)

Вопросы по программе:
В итоге получилось что-то написать, однако, похоже, что клиент зацикливается и через некоторое время вылетает исключение OutOfMemory. Где ошибка и как бы ее исправить?

Буду очень признателен, если ответ будет с примерами.

Клиент:
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Text;
using AsyncClientApp.Communication;
using System.Net;
using System.Threading;
 
namespace AsyncClientApp
{
    public static class Client
    {
        static MainForm mainForm;
 
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(mainForm = new MainForm());
        }
 
        // ManualResetEvent instances signal completion.
        private static ManualResetEvent connectDone = new ManualResetEvent(false);
        private static ManualResetEvent receiveDone = new ManualResetEvent(false);
 
        // The response from the remote device.
        private static String _response = String.Empty, _message = String.Empty;
        private static bool isBusy = false, isStarted = false;
 
        private static Socket client;
 
        public static String Message
        {
            get
            {
                return _message;
            }
            set
            {
                if (value != _message)
                    _message = value;
            }
        }
 
        public static void StartClient()
        {
            if (!isStarted && !isBusy)
            {
                try
                {
                    // Establish the remote endpoint for the socket.
                    IPHostEntry ipHostInfo = Dns.Resolve("192.168.100.46");
                    IPAddress ipAddress = ipHostInfo.AddressList[0];
                    IPEndPoint remoteEP = new IPEndPoint(ipAddress, 2017);
 
                    // Create a TCP/IP socket.
                    client = new Socket(AddressFamily.InterNetwork,
                    SocketType.Stream, ProtocolType.Tcp);
 
                    // Connect to the remote endpoint.
                    isBusy = true;
                    client.BeginConnect(remoteEP,
                    new AsyncCallback(ConnectCallback), client);
                    connectDone.WaitOne();
 
                    //When connected to server side
                    isStarted = true;
                    isBusy = false;
 
                    while (true)
                    {
                        // Receive the response from the remote device.
                        Receive(client);
                        receiveDone.WaitOne();
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }
        }
 
        public static void CloseClient()
        {
            if (isStarted)
            {
                client.Shutdown(SocketShutdown.Both);
                client.Close();
            }
        }
 
        private static void ConnectCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.
                Socket client = (Socket)ar.AsyncState;
 
                // Complete the connection.
                client.EndConnect(ar);
 
                Console.WriteLine("Socket connected to {0}",
                client.RemoteEndPoint.ToString());
 
                // Signal that the connection has been made.
                connectDone.Set();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
 
        private static void Receive(Socket client)
        {
            try
            {
                // Create the state object.
                StateObject state = new StateObject();
                state.workSocket = client;
 
                // Begin receiving the data from the remote device.
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReceiveCallback), state);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
 
            if (!isBusy && Message != String.Empty)
            {
                Send(client, Message);
                Message = String.Empty;
            }
 
            receiveDone.Set();
        }
 
        private static void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the state object and the client socket
                // from the asynchronous state object.
                StateObject state = (StateObject)ar.AsyncState;
                Socket client = state.workSocket;
 
                // Read data from the remote device.
                int bytesRead = client.EndReceive(ar);
 
                if (bytesRead > 0)
                {
                    isBusy = true;
                    // There might be more data, so store the data received so far.
                    state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
 
                    // Get the rest of the data.
                    client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReceiveCallback), state);
                }
                else if (isBusy)
                {
                    // All the data has arrived; put it in response.
                    if (state.sb.Length > 1)  mainForm.Response = state.sb.ToString();
                    isBusy = false;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
 
        private static void Send(Socket client, String data)
        {
            // Convert the string data to byte data using ASCII encoding.
            byte[] byteData = Encoding.ASCII.GetBytes(data);
 
            // Begin sending the data to the remote device.
            client.BeginSend(byteData, 0, byteData.Length, 0,
            new AsyncCallback(SendCallback), client);
        }
 
        private static void SendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.
                Socket client = (Socket)ar.AsyncState;
 
                // Complete sending the data to the remote device.
                int bytesSent = client.EndSend(ar);
                Console.WriteLine("Sent {0} bytes to server.", bytesSent);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
    }
}

Сервер:
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
 
namespace AsyncServerApp
{
    public class StateObject
    {
        // Client socket.
        public Socket workSocket = null;
        // Size of receive buffer.
        public const int BufferSize = 1024;
        // Receive buffer.
        public byte[] buffer = new byte[BufferSize];
        // Received data string.
        public StringBuilder sb = new StringBuilder();
    }
 
    class Server
    {
        // Thread signal.
        public static ManualResetEvent allDone = new ManualResetEvent(false);
 
        public Server()
        {
        }
 
        public static void StartListening()
        {
            // Data buffer for incoming data.
            byte[] bytes = new Byte[1024];
 
            // Establish the local endpoint for the socket.
            IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
            IPAddress ipAddress = ipHostInfo.AddressList[0];
            IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 2017);
 
            // Create a TCP/IP socket.
            Socket listener = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);
 
            // Bind the socket to the local endpoint and listen for incoming connections.
            try
            {
                listener.Bind(localEndPoint);
                listener.Listen(100);
 
                while (true)
                {
                    // Set the event to nonsignaled state.
                    allDone.Reset();
 
                    // Start an asynchronous socket to listen for connections.
                    Console.WriteLine("Waiting for a connection...");
                    listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
 
                    // Wait until a connection is made before continuing.
                    allDone.WaitOne();
                }
 
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
 
            Console.WriteLine("\nPress ENTER to continue...");
            Console.Read();
        }
 
        public static void AcceptCallback(IAsyncResult ar)
        {
            // Signal the main thread to continue.
            allDone.Set();
 
            // Get the socket that handles the client request.
            Socket listener = (Socket)ar.AsyncState;
            Socket handler = listener.EndAccept(ar);
 
            // Create the state object.
            StateObject state = new StateObject();
            state.workSocket = handler;
            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReadCallback), state);
        }
 
        public static void ReadCallback(IAsyncResult ar)
        {
            String content = String.Empty;
            // Retrieve the state object and the handler socket
            // from the asynchronous state object.
            StateObject state = (StateObject)ar.AsyncState;
            Socket handler = state.workSocket;
 
            // Read data from the client socket.
            int bytesRead = handler.EndReceive(ar);
 
            if (bytesRead > 0)
            {
                // There might be more data, so store the data received so far.
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
 
                // Check for end-of-file tag. If it is not there, read
                // more data.
                content = state.sb.ToString();
 
                // All the data has been read from the
                // client. Display it on the console.
                Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", content.Length, content);
                
                // Not all data received. Get more.
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReadCallback), state);
            }
            else
            {
                // Echo the data back to the client.
                state.sb.Clear();
                Send(handler, DateTime.Now.ToString("hh.mm.ss.ffffff"));
            }
        }
 
        private static void Send(Socket handler, String data)
        {
            // Convert the string data to byte data using ASCII encoding
            byte[] byteData = Encoding.ASCII.GetBytes(data);
 
            // Begin sending the data to the remote device.
            handler.BeginSend(byteData, 0, byteData.Length, 0,
            new AsyncCallback(SendCallback), handler);
        }
 
        private static void SendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.
                Socket handler = (Socket)ar.AsyncState;
 
                // Complete sending the data to the remote device.
                int bytesSent = handler.EndSend(ar);
                Console.WriteLine("Sent {0} bytes to client.", bytesSent);
 
                //handler.Shutdown(SocketShutdown.Both);
                //handler.Close();
 
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
 
 
        public static int Main(String[] args)
        {
            StartListening();
            return 0;
        }
    }
}
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
17.08.2015, 09:58
Ответы с готовыми решениями:

Ответ от асинхронного сервера
Добра. Решил написать асинхронный сервер. Сначала полёт был отличный. Писал опираясь на статью (Почти копипаста) Всё работает...

Завершение асинхронного сервера
Есть форма в которой асинхронный сервер запускается и останавливается. Когда нажимаю старт сервер запускается, всё написано так: public...

Создание асинхронного сервера на основе сокетов с пользователями
Давно курю эту тему... Смысл в том, что мне нужно написать асинхронный сервер на сокетах (System.Net.Sockets). Как это сделать я, в...

8
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
17.08.2015, 10:00
Цитата Сообщение от Blueeyer Посмотреть сообщение
Пытался сделать следующее:
Blueeyer, а в чем суть ваших манипуляций? Какой конечный результат желаете получить? Если можно, вкратце функционал вашей программы.
А то много букафф, но смысл не совсем понятен (по крайней мере, для меня), а гадать не хочется.
0
12 / 12 / 7
Регистрация: 09.10.2013
Сообщений: 222
17.08.2015, 10:07  [ТС]
Хочу написать игру, сервер должен постоянно отправлять всем подключившимся коорденаты всех ближайших объектов, в то же время - подключившиеся игроки способны отправлять команду о том, что они желают передвинуться в определенном направлении, сервер делает вычисления по полученной команде и отправляет новое расположение игрока всем остальным.
0
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
17.08.2015, 10:10
Blueeyer, вариант использования WCF с обратными вызовами не рассматривали?
В ветке по WCF есть недавняя тема. по созданию чата, вот как раз оттуда и можете взять куски кода, задачи-то похожи. При чате отправляются сообщения, а при вашем варианте - координаты объекта.
1
12 / 12 / 7
Регистрация: 09.10.2013
Сообщений: 222
17.08.2015, 10:12  [ТС]
Можно посмотреть, конечно. Просто интересен сам процесс написания таким образом. Хотелось бы немного изучить это и получить ответы на давно интересующие вопросы.
0
Эксперт .NET
 Аватар для insite2012
5548 / 4311 / 1218
Регистрация: 12.10.2013
Сообщений: 12,371
Записей в блоге: 2
17.08.2015, 10:14
Цитата Сообщение от Blueeyer Посмотреть сообщение
Можно посмотреть, конечно.
Смотрите.
Отправка сообщений клиенту
1
12 / 12 / 7
Регистрация: 09.10.2013
Сообщений: 222
18.08.2015, 08:55  [ТС]
Благодарю. Рассмотрю исходники и в случае чего - еще обращусь с вопросами )

Добавлено через 2 минуты
Но, по возможности, если кто сможет - прошу ответить и на мои предыдущие вопросы. Долгое время держал их в голове.

Добавлено через 22 часа 34 минуты
Еще актуально
0
12 / 12 / 7
Регистрация: 09.10.2013
Сообщений: 222
05.11.2015, 15:44  [ТС]
Актуально
0
2 / 2 / 1
Регистрация: 04.11.2015
Сообщений: 23
05.11.2015, 16:05
Лучший ответ Сообщение было отмечено tezaurismosis как решение

Решение

1) Правильно ли это? Постоянно слушать/ожидать пакеты.
* Других вариантов лично я и не знаю

2) Можно ли каким-то образом и принимать данные и отправлять одновременно (может в нескольких потоках)?
* Не понял вопроса. Но потоки это зло которое делает выполнения кода хаотичным Лучше избегать создание лишних потоков.

3) Стоит ли каждого подключенного клиента кидать в отдельный поток? (Если кол-во подключений может дойти до 1-5 тыс.)
* Отдельные потоки - можно но как по мне, создание отдельного процесса со своим кэшем для каждого пользователя - вполне логичней

4) Можно ли как-то прослеживать кол-во отправленных пакетов в секунду? Можно ли ограничивать?
* Что значит ограничить не понял. Вы сами говорите клиенту когда и что нужно отправить на сервер.

5) Данный вопрос исходит из 2 и 3. 5 тыс. подключений + каждое подключение слушает и отправляет в своем потоке. 10-15 тыс. потоков - это огромное кол-во? Какие последствия?
* Не имеет значение кол-во подключений, у каждого подключения свой порт. Но опять же таки, я бы создал одно поточное приложение для каждого клиента, и при каждом новом подключении вызывал бы новый процесс.

6) Сколько, вообще, потоков можно открывать? (В норме)
* Открыть, сколько душа желает! Обрабатывается одновременно до 2-ух на одно ядро.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
05.11.2015, 16:05
Помогаю со студенческими работами здесь

Найти ошибку в коде Клиента для асинхронного I/O
Доброе время суток. Помогите пожалуйста разобраться и найти ошибку в коде Клиента для асинхронного I/O. При компиляции клиента приложение...

Реализация асинхронного вызова операций WCF
Добрый день. При создании службы WCF, с возможностью асинхронного вызова метода, столкнулся с следующей проблемой. При объявлении...

Клиента Сервера
Всем привет. В общем я с другом создаю проект, в котором друг пишет сайт на php, а я создаю клиент на Delphi. Вот скриншоты моего клиенты....

Ошибки сервера и клиента
Здравствуйте. У меня ситуация такая. Есть сервис развернутый на ASP.NET, есть клиент, написанный на WinForms. Когда запускаю сервис на...

Связь клиента и сервера
Продолжаю мучить Lua. Нагуглил примеры работы с сокетами, теперь эксперементирую. Вот накатал две программки (тег Lua не нашел,...


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

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru