Форум программистов, компьютерный форум, киберфорум
Наши страницы
C# .NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.61/23: Рейтинг темы: голосов - 23, средняя оценка - 4.61
lawliet93
17 / 5 / 3
Регистрация: 22.03.2011
Сообщений: 329
1

Клиент-сервер: Как определить, что клиент отключился?

28.01.2013, 16:27. Просмотров 4345. Ответов 4
Метки нет (Все метки)

Привет. Есть клиент и сервер, при подключении клиента, на сервере создается класс, который содержит копию сокета и всякую инфу клиента, и каждый такой класс добавляется в коллекцию List, чтобы потом была возможность отправлять сообщение сразу всем клиентам. Но если клиент отключится, то нужно будет удалить его класс из коллекции, так как определить, что сокет отключился? я вот так делаю:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 private void CheckClients()
        {
            while (true)
            {
                foreach (ClientConnection cl in c.Clients)
                {
                    if (!cl.Sock.Connected)
                    {
                        c.Clients.Remove(cl);
                        Console.WriteLine("del1");
                    }
                }
                Thread.Sleep(3000);
            }
        }
но так ниче не работает =\
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
28.01.2013, 16:27
Ответы с готовыми решениями:

Клиент-серверное приложение: как определить, что сервер/клиент не отвечает в течении определенного времени
Пишу клиент-серверное приложение. Использую TCPListener и TCPClient. Вопрос:...

Как узнать что удаленный клиент отключился
Здравствуйте. При подключение клиента создается список клиентов ...

Клиент-сервер. Клиент не принимает данные
Здравствуйте о светлейшие умы сего мира! Я работаю над одним проектом, а именно...

Что почитать (Лучше поконкретнее), чтобы научиться работать с клиент-сервер?
Вообщем, разговаривал я с одним человеком и всплыла такая идея: Написать...

Клиент-Сервер: как реализовать
Во общем есть Сервер на Ansi-C Задача:нужно написать клиента C# Данные...

4
kolorotur
Эксперт .NET
10617 / 8798 / 2195
Регистрация: 17.09.2011
Сообщений: 15,075
Завершенные тесты: 1
28.01.2013, 17:14 2
Если клиент отключился "нормальным" образом, то на сервер придет сообщение длиной в 0 байт.
Если соединение оборвалось, то у вас вылетит исключение при следующей попытке отправить что-то этому клиенту - в этот момент и удаляйте его из коллекции (именно поэтому во всяких чятиках отвалившиеся некоторе время висят в списке присутствующих).
1
lawliet93
17 / 5 / 3
Регистрация: 22.03.2011
Сообщений: 329
28.01.2013, 18:11  [ТС] 3
Цитата Сообщение от kolorotur Посмотреть сообщение
Если клиент отключился "нормальным" образом, то на сервер придет сообщение длиной в 0 байт.
Если соединение оборвалось, то у вас вылетит исключение при следующей попытке отправить что-то этому клиенту - в этот момент и удаляйте его из коллекции (именно поэтому во всяких чятиках отвалившиеся некоторе время висят в списке присутствующих).
понятненько. сяп за ответ :3

Добавлено через 51 минуту
Цитата Сообщение от kolorotur Посмотреть сообщение
Если клиент отключился "нормальным" образом, то на сервер придет сообщение длиной в 0 байт.
Если соединение оборвалось, то у вас вылетит исключение при следующей попытке отправить что-то этому клиенту - в этот момент и удаляйте его из коллекции (именно поэтому во всяких чятиках отвалившиеся некоторе время висят в списке присутствующих).
у мя еще 1 вопрос. а какое это - "нормальное" отключение? у меня оно вот такое
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
while (true)
            {
                s = Console.ReadLine();
                SendAsync(Encoding.UTF8.GetBytes(s));
                if (s == "end")
                {
                    socket.Disconnect(false);
                    Console.WriteLine("after disc");
                    socket.Close();
                    Console.WriteLine("after close");
                    Console.Read();
                }
            }
ну это в клиенте, а на сервере вот так написал
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
 try
                {
                    Console.WriteLine("bytes trans = " + e.BytesTransferred);
                    if (e.BytesTransferred == 0)
                    {
                        foreach (ClientConnection cl in c.Clients)
                        {
                            if (cl.ClientID == ClientID)
                            {
                                c.Clients.Remove(cl);
                                Console.WriteLine("del1");
                            }
                        }
                    }
                    else
                    {
 
                        string str = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
                        Console.WriteLine("Incoming msg from #{0}: {1}", ClientNumber, str);
                        SendToAll(str);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
Один раз я набрал end в клиенте, и вижу - на сервере удалился один клиент, потом открыл 3 клиента и в каждом написал end и ни один не сработал так, как надо. На сервер пришло только слово end, а 0 байт не приходило =\
0
kolorotur
Эксперт .NET
10617 / 8798 / 2195
Регистрация: 17.09.2011
Сообщений: 15,075
Завершенные тесты: 1
28.01.2013, 18:37 4
Покажите как происходит отправка сообщения клиентом и получение его сервером.
0
lawliet93
17 / 5 / 3
Регистрация: 22.03.2011
Сообщений: 329
29.01.2013, 14:32  [ТС] 5
Цитата Сообщение от kolorotur Посмотреть сообщение
Покажите как происходит отправка сообщения клиентом и получение его сервером.
отправка
C#
1
2
3
4
5
6
7
8
9
10
11
private static void SendAsync(byte[] data)
        {
            if (socket.Connected && data.Length > 0)
            {
                SocketAsyncEventArgs e = new SocketAsyncEventArgs();
                e.SetBuffer(data, 0, data.Length);
                e.Completed += SockAsyncArgs_Completed;
                bool willRaiseEvent = socket.SendAsync(e);
                Console.WriteLine("send async");
            }
        }
прием
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
 private void ProcessReceive(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                SockAsyncEventArgs.UserToken = false;
                try
                {
                    Console.WriteLine("bytes trans = " + e.BytesTransferred);
                    if (e.BytesTransferred == 0)
                    {
                        foreach (ClientConnection cl in c.Clients)
                        {
                            if (cl.ClientID == ClientID)
                            {
                                c.Clients.Remove(cl);
                                Console.WriteLine("del1");
                            }
                        }
                    }
                    else
                    {
 
                        string str = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
                        Console.WriteLine("Incoming msg from #{0}: {1}", ClientNumber, str);
                        SendToAll(str);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
а вот весь код клиента и сервера, на всяк случай
Кликните здесь для просмотра всего текста

клиент:
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
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
 
namespace test_client
{
    class Program
    {
        private static Socket socket;
        private static SocketAsyncEventArgs SockAsyncEventArgs; // объект для асинхронной операции на сокете
 
        private static byte[] buff; // буфер обмена
 
        private static void Init()
        {
 
 
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            buff = new byte[256];
            SockAsyncEventArgs = new SocketAsyncEventArgs();
            // подписываемся на завершение асинхронного соединения
            SockAsyncEventArgs.Completed += SockAsyncArgs_Completed;
        }
        private static void res()
        {
            try
            {
                while (true)
                {
                    if (socket.Available != 0) //если пришли данные
                    {
 
                        //Thread.Sleep(500);
                        ProcessSend(SockAsyncEventArgs); // получаем их
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
 
        private static void SockAsyncArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Connect:
                    ProcessConnect(e);
                    break;
                case SocketAsyncOperation.Receive:
                    ProcessReceive(e);
                    break;
            }
        }
 
        private static void Start_Connect(string address, int port)
        {
            SockAsyncEventArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(address), port);
            ConnectAsync(SockAsyncEventArgs);
        }
 
        private static void ConnectAsync(SocketAsyncEventArgs e)
        {
            bool willRaiseEvent = socket.ConnectAsync(e);
            if (!willRaiseEvent)
                ProcessConnect(e);
        }
 
        private static void ProcessConnect(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                SockAsyncEventArgs.SetBuffer(buff, 0, buff.Length);
                res();
            }
            else
                Console.WriteLine("Lost connection with " + e.RemoteEndPoint.ToString());
 
        }
 
        private static void SendAsync(byte[] data)
        {
            if (socket.Connected && data.Length > 0)
            {
                SocketAsyncEventArgs e = new SocketAsyncEventArgs();
                e.SetBuffer(data, 0, data.Length);
                e.Completed += SockAsyncArgs_Completed;
                bool willRaiseEvent = socket.SendAsync(e);
                Console.WriteLine("send async");
            }
        }
 
        private static void ProcessSend(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                ReceiveAsync(SockAsyncEventArgs);
            }
            else
            {
                Console.WriteLine("Not sended");
            }
        }
 
        private static void ReceiveAsync(SocketAsyncEventArgs e)
        {
            bool willRaiseEvent = socket.ReceiveAsync(e);
            if (!willRaiseEvent)
                ProcessReceive(e);
        }
 
        private static void ProcessReceive(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                string s = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred); //получаем идентификатор команды
                Console.WriteLine(s);
 
            }
 
        }
        static int Main(string[] args)
        {
            Init(); //подготовка соединения  с сервером
            Start_Connect("127.0.0.1", 9090); //соединяемся с сервером
            string s = "";
 
            while (true)
            {
                s = Console.ReadLine();
                SendAsync(Encoding.UTF8.GetBytes(s));
                if (s == "end")
                {
                    socket.Disconnect(false);
                    Console.WriteLine("after disc");
                    socket.Close();
                    Console.WriteLine("after close");
                    Console.Read();
                }
            }
            return 0;
        }
 
    }
 
}
сервер:
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
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Collections.Generic;
 
namespace NewServer1
{
    class Clc
    {
        public List<ClientConnection> Clients = new List<ClientConnection>();
    }
 
    class Server
    {
        private Socket Sock;
        private SocketAsyncEventArgs AcceptAsyncArgs;
        private Clc c = new Clc();
 
        public Server()
        {
            Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            AcceptAsyncArgs = new SocketAsyncEventArgs();
            AcceptAsyncArgs.Completed += AcceptCompleted;
        }
        public void Start(int Port)
        {
            Sock.Bind(new IPEndPoint(IPAddress.Any, Port));
            Sock.Listen(50);
            AcceptAsync(AcceptAsyncArgs);
            ViewNum();
        }
        private void AcceptAsync(SocketAsyncEventArgs e)
        {
            bool willRaiseEvent = Sock.AcceptAsync(e);
            if (!willRaiseEvent)
                AcceptCompleted(Sock, e);
        }
        private void AcceptCompleted(object sender, SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                ClientConnection Client = new ClientConnection(e.AcceptSocket, c);
                c.Clients.Add(Client);
            }
            e.AcceptSocket = null;
            AcceptAsync(AcceptAsyncArgs);
        }
        private void CheckClients()
        {
            while (true)
            {
                foreach (ClientConnection cl in c.Clients)
                {
                    if (!cl.Sock.Connected)
                    {
                        c.Clients.Remove(cl);
                        Console.WriteLine("del1");
                    }
                }
                Thread.Sleep(3000);
            }
        }
        public void ViewNum()
        {
            while (true)
            {
 
                Console.WriteLine(c.Clients.Count);
                Thread.Sleep(3000);
            }
        }
        public void Stop()
        {
            Sock.Close();
        }
    }
    class ClientConnection
    {
        public int ClientID;
        private Clc c = new Clc();
        public static int ClientNumber = 0;
        private static Server srv = new Server();
        public Socket Sock;
        private SocketAsyncEventArgs SockAsyncEventArgs;
        private byte[] buff;
        public ClientConnection(Socket AcceptedSocket, Clc cl)
        {
            c = cl;
            ClientNumber++;
            ClientID = ClientNumber;
            buff = new byte[1024];
            Sock = AcceptedSocket;
            SockAsyncEventArgs = new SocketAsyncEventArgs();
            SockAsyncEventArgs.Completed += SockAsyncEventArgs_Completed;
            SockAsyncEventArgs.SetBuffer(buff, 0, buff.Length);
 
            ReceiveAsync(SockAsyncEventArgs);
        }
 
 
        private void SockAsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Receive:
                    ProcessReceive(e);
                    break;
                case SocketAsyncOperation.Send:
                    ProcessSend(e);
                    break;
            }
        }
        private void ReceiveAsync(SocketAsyncEventArgs e)
        {
            bool willRaiseEvent = Sock.ReceiveAsync(e);
            e.UserToken = true;
            if (!willRaiseEvent)
                ProcessReceive(e);
        }
 
        private void ProcessReceive(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                SockAsyncEventArgs.UserToken = false;
                try
                {
                    Console.WriteLine("bytes trans = " + e.BytesTransferred);
                    if (e.BytesTransferred == 0)
                    {
                        foreach (ClientConnection cl in c.Clients)
                        {
                            if (cl.ClientID == ClientID)
                            {
                                c.Clients.Remove(cl);
                                Console.WriteLine("del1");
                            }
                        }
                    }
                    else
                    {
 
                        string str = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
                        Console.WriteLine("Incoming msg from #{0}: {1}", ClientNumber, str);
                        SendToAll(str);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
        public void SendAsync(string data)
        {
            byte[] buff = Encoding.UTF8.GetBytes(data);
            SocketAsyncEventArgs e = new SocketAsyncEventArgs();
            e.Completed += SockAsyncEventArgs_Completed;
            e.SetBuffer(buff, 0, buff.Length);
            SendAsync(e);
            Console.WriteLine("Send Async");
        }
 
        private void SendAsync(SocketAsyncEventArgs e)
        {
            bool willRaiseEvent = Sock.SendAsync(e);
            Console.WriteLine("sock  = " + willRaiseEvent);
            if (!willRaiseEvent)
                ProcessSend(e);
        }
        private void ProcessSend(SocketAsyncEventArgs e)
        {
            if ((bool)SockAsyncEventArgs.UserToken == false)
                if (e.SocketError == SocketError.Success)
                    ReceiveAsync(SockAsyncEventArgs);
        }
        public void SendToAll(string data)
        {
            foreach (ClientConnection Cl in c.Clients)
            {
                Cl.SendAsync(data);
            }
        }
        public void Check()
        {
        
            while (true)
            {
                foreach (ClientConnection cl in c.Clients)
                {
                    if (!cl.Sock.Connected)
                    {
                        c.Clients.Remove(cl);
                        Console.WriteLine("del1");
                    }
                }
                Thread.Sleep(1000);
            }
        }
    }
    class Program
    {
 
        static void Main(string[] args)
        {
 
            int Port = 9090;
            Server srv = new Server();
            srv.Start(Port);
            Console.WriteLine("Server started on port {0}, press any key to stop him...", Port);
            Console.Read();
            srv.Stop();
        }
    }
}


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

Добавлено через 1 час 16 минут
в общем я разобрался с проблемой, что когда отключился клиент и сервер пытается ему отослать что-то, то не происходит исключения. Вся суть была в этом методе
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 private void SendAsync(SocketAsyncEventArgs e)
        {
            bool willRaiseEvent = Sock.SendAsync(e);
            Console.WriteLine("sock  = " + willRaiseEvent);
            if (!willRaiseEvent)
            {
                foreach (ClientConnection cl in c.Clients)
                {
                    if (cl.ClientID == ClientID)
                    {
                        c.Clients.Remove(cl);
                        Console.WriteLine("del2");
                    }
                }
            }
                //ProcessSend(e);
        }
Если удалось отослать, то willRaiseEvent = True, если не удалось, то False. Вот и исключения не было никакого. А на счет стандартного закрытия сокета я так и не разобрался, оно то шлет 0 байтов, то не шлет. Я, перед стандартным закрытием, буду вручную отсылать 0 байт и все дела.
1
29.01.2013, 14:32
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.01.2013, 14:32

Как написать небольшой клиент-сервер
Всем привет. Мне нужно написать два приложения: Первое пустое, оно выступает...

Как написать простой клиент-сервер
Доброго времени суток господа. Возникла маленькая проблемка. Пытаюсь...

Как красиво организовать клиент-сервер
Здравствуйте! Пишу приложение: сервер бесконечно ждет подключения нового...


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru