Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Socket client+server передается и принимается толь


Автор: 123456789igor 6.5.2014, 02:46
Я хочу постоянно передавать от сервера клиенту массив байт, но получается передать только 1 раз. Никак не пойму почему.
Сервер:
Код

public ServerSocket(IPAddress ipAddress, int port)
        {
            _clients = new List<ClientModel>();

            _server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _server.Bind(new IPEndPoint(ipAddress, port));
            _server.Listen(20); 
            Accept();
        }

        private async void Accept()
        {
            
            for ( int i=0;i<10 ;i++)
            {
                var socket = await Task.Factory.FromAsync<Socket>(_server.BeginAccept, _server.EndAccept, true);
                var newClient = new ClientModel
                {
                    Id = _id++,
                    ClientSocket = socket
                };
                _clients.Add(newClient);
                await Send(1, "hello " + i + "");
            }
        }
public async Task Send(int id, String data)
        {
            var client = _clients.FirstOrDefault(cl => cl.Id == id);
            if(client == null) return;

            var byteData = Encoding.UTF8.GetBytes(data);
            await Task.Factory.FromAsync<int>(
              client.ClientSocket.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, null, client.ClientSocket),
              client.ClientSocket.EndSend);
        }


Клиент:
Код

public ClientSocket()
        {
            _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        public bool Connect(IPAddress ipAddress, int port)
        {
            _client.Connect(ipAddress, port);
            if (!_client.Connected)
            {
                return false;
            }
            Receive();
            return true;
        }

private async void Receive()
        {
            var buffer = new byte[4096];
            for (; ; )
            {
                try
                {
                    var bytesRead = await Task.Factory.FromAsync<int>(
                            _client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, null, _client),
                             _client.EndReceive);
                    if (bytesRead <= 0) continue;

                    var message = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    Console.WriteLine(message);
                }
                catch
                {
                    break;
                }
            }


Учитывать надо, что одновременных клиентов может быть несколько. Проблема в том, что на 2ой итерации Сервер ждет на "BeginAccept/EndAccept", а клиент на "BeginReceive/EndReceive". Т.е получается, что клиент готов получать, а сервер не знает об этом. Подскажите как решить проблему.
Интересный факт: Если запустить сервер, затем клиент, то передастся массив 1 раз. Но если(ничего не закрываяя) открыть новый экземпляр клиента и выполнить его, то первый экземпляр пример 2ой раз массив. Если 2ой экземпляр клиента выполнить ещё раз, то первый примет 3ий массив. И так далее

Автор: Экскалупатор 6.5.2014, 11:22
а почему не устраивает классический подход? когда сервер ничего ни о ком не знает и отвечает только на запросы клиента(как в идеале и должно быть). т.е. клиент делает запрос, сервер отдает ему пачку данных, клиент ее получает обрабатывает и сообщает серверу о том, что все принял и готов к следующей отправке или о том, что что то сломалось и предыдущая отправка не прошла и ее надо еще раз отправить. так будет ровнее все это выглядеть и работать. и лучше что бы сервер не хранил состояние, тогда будет меньше зависимостей и потенциальных точек отказа.


З.Ы. а перестает слать, очевидно, из-за того, что закрывается соединение и сервер не инициирует новое(и это правильно).

Автор: 123456789igor 6.5.2014, 14:34
Цитата(Экскалупатор @ 6.5.2014,  11:22)
а почему не устраивает классический подход? когда сервер ничего ни о ком не знает и отвечает только на запросы клиента(как в идеале и должно быть). т.е. клиент делает запрос, сервер отдает ему пачку данных, клиент ее получает обрабатывает и сообщает серверу о том, что все принял и готов к следующей отправке или о том, что что то сломалось и предыдущая отправка не прошла и ее надо еще раз отправить. так будет ровнее все это выглядеть и работать. и лучше что бы сервер не хранил состояние, тогда будет меньше зависимостей и потенциальных точек отказа.


З.Ы. а перестает слать, очевидно, из-за того, что закрывается соединение и сервер не инициирует новое(и это правильно).

Можно по подробнее? Как это реализовать? Получается на стороне сервера и не нужен цикл? или я не так понял?

Автор: 123456789igor 6.5.2014, 15:09
Думаю просто не хватает каких то колбэков что бы снова связать клиент и сервер. Но каких не могу понять

Автор: Экскалупатор 6.5.2014, 15:30
Цитата(123456789igor @  6.5.2014,  13:34 Найти цитируемый пост)
Можно по подробнее? Как это реализовать? Получается на стороне сервера и не нужен цикл? или я не так понял? 


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

Цитата(123456789igor @  6.5.2014,  14:09 Найти цитируемый пост)
Думаю просто не хватает каких то колбэков что бы снова связать клиент и сервер. Но каких не могу понять 

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

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

Добавлено через 3 минуты и 31 секунду
http://habrahabr.ru/company/microsoft/blog/145178/ может будет интересно, вместо сокетов(хотя смотря для каких задач использовать)

Автор: 123456789igor 7.5.2014, 20:16
если у сервера убрать цикл, то все равно только 1 раз отправляет

Автор: Экскалупатор 7.5.2014, 20:42
Цитата(123456789igor @  7.5.2014,  19:16 Найти цитируемый пост)
если у сервера убрать цикл, то все равно только 1 раз отправляет 

какой именно цикл имеется ввиду? сервер должен выполнять в цикле операцию обработки входящих запросов. т.е.
1. сервер стартует
2. привязывается к порту
3. ждет подключения
4. при подключении создает поток для обработки 
5. запускает его(сам в процессе не учавствует)
6. возвращаемся к пункту 3.


з.ы. Про то что не нужен цикл, я имел ввиду что не нужно в цикле отдавать много ответов на один запрос.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)