Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ под Linux
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.50/10: Рейтинг темы: голосов - 10, средняя оценка - 4.50
Fukki
0 / 0 / 0
Регистрация: 17.12.2009
Сообщений: 2
#1

Ошибка при закрытии неблокирующего сокета со стороны клиента

20.12.2009, 16:44. Просмотров 1889. Ответов 2
Метки нет (Все метки)

Здравствуйте, уважаемые.
Столкнулся с такой вот проблемой. Сделал набросок сервера на неблокирующих сокетах, вродебы все сносно и можно было бы двигаться дальше, но возник ряд проблем при обработке сокетов, закрытых со стороны клиента. Причем, если соединение эмулировалось телнетом, а потом было закрыто - все нормально, сокет нормально закрывается и со стороны сервера, если же клиента эмулировать как делал я (стандартный класс TClientSocket Delphi), и разрывать соединение хотя бы через Client.Active:=False; или
програмно убивать процесс с клиентом, сокет начинает посылать пустые датаграммы, а при попытка его закрыть со стороны сервера приводит к такой ошибке:

_cygtls::handle_exceptions: Exception: STATUS_ACCESS_VIOLATION

Как я понял это просто ошибка доступа к занятому ресурсу, однако опыта в программировании C/C++ Linux у меня почти нет, поэтому решил обратиться на форум. Сорцы сервера внизу, клиент, я думаю смысла скидывать нет - там все прозрачно.


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
#define ENV_POSIX
#include <stdio.h>
#include <iostream>
#include <string>
#include <unistd.h>
#include <set>
#include <algorithm>
 
#ifdef ENV_POSIX
       #include <sys/types.h>
       #include <sys/socket.h>
       #include <netinet/in.h>
       #include <signal.h>
       #include <fcntl.h>
       #include <pthread.h>
#else
       #include <winsock2.h>
#endif
 
using namespace std;
 
void * Socks(void*);
 
 
 
int main (int argc, char **argv)
{
        int id1=1;
        int result;
        pthread_t pSockThread;
        result = pthread_create(&pSockThread, NULL, Socks, &id1);
 
    if(result!=0)
    {
        cout << "thread cr8ing failure!" << endl;
        return EXIT_FAILURE;
    }
    
    while(1)
    {
    //  cout << "main_thread is running!" << endl;
        sleep(1);
    }
}
 
 
 
void * Socks(void* a)
{
      /*variables declaration */
      struct sockaddr_in dst;
 
      #ifdef ENV_POSIX
            int sock, sock_id;
      #else
            SOCKET sock, sock_id;
        WSADATA wsaData;
      #endif
 
      const short int port=5000;
      const short int sock_backlog=200;
      int len = sizeof(struct sockaddr);
      int bytes_read =0;
      char buf[512];
      fd_set sock_readset,sock_errorset;
      set<int> sock_clients;
      set<int>::iterator it;
      timeval sock_timeout;
      sock_timeout.tv_sec = 3;
      sock_timeout.tv_usec = 0;
 
 
 
 
      #ifdef ENV_POSIX
            signal(SIGPIPE, SIG_IGN);
      #else
            cout << "Testing if the WinSock2 version is equal or higher than 2.1...");
            
            if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0)
        {
                  cout << "failed!" << endl;
                  return 1;
            }
            cout << "ok!" << endl;
      #endif
 
      //filling of sockaddr_in structure
      dst.sin_family = AF_INET;
      dst.sin_addr.s_addr = htonl(INADDR_ANY);
      dst.sin_port = htons(port);
 
      //initializing and binding socket
      sock = socket(AF_INET,SOCK_STREAM,0);
      fcntl(sock, F_SETFL, O_NONBLOCK);
      cout << "Waiting for an incoming connection..." << endl;
      bind(sock,(struct sockaddr*)&dst,len);
      listen(sock,sock_backlog);
      int k=0;
 
      while(1)
      {
        cout << "sock_thread is running!-----" << endl;
        int mx=0;
        FD_ZERO(&sock_readset);
        FD_ZERO(&sock_errorset);
        FD_SET(sock, &sock_readset);
        
            for(it = sock_clients.begin(); it != sock_clients.end(); it++)
            {
              FD_SET(*it, &sock_readset);
        }
        mx = max(sock, *max_element(sock_clients.begin(), sock_clients.end()));
 
        //wating for datagrams from clients
 
        if(int errno=select(mx+1, &sock_readset, NULL, &sock_errorset, &sock_timeout) <= 0)
            {
                  cout<<"no data from socks...errno: -"<< errno <<endl;
                  continue;
            }
 
            for(it = sock_clients.begin(); it != sock_clients.end(); it++)
            {
                 if(FD_ISSET(*it, &sock_errorset))
                 {
                      cout<<"error socket det-d"<<endl;
                      close(*it);
                 }
        }
 
            if(FD_ISSET(sock, &sock_readset))
            {
                  //accepting new connection
                  //sock_id = accept(sock,(struct sockaddr*)&dst,&len);
                  //sock_id = accept(sock,NULL,NULL);
                  sock_id = accept(sock, NULL, NULL);
                  if(sock_id < 0)
                  {
                         cout<<"sock accepting error!"<<endl;
 
                  }
          else
          {
                         fcntl(sock_id, F_SETFL, O_NONBLOCK);
                         sock_clients.insert(sock_id);
          }
 
             }
             
             for(it = sock_clients.begin(); it != sock_clients.end(); it++)
             {
                   if(FD_ISSET(*it, &sock_readset))
                   {
                         // data receiving
                         bytes_read = recv(*it, &buf, 1024, 0);
             cout << "inc data "<<*it/sizeof(*it)<<endl;
 
             if(bytes_read == 0)
                     {
                                // closing socket
                                #ifdef ENV_POSIX
                               close(*it);
                        #else
                               closesocket(*it);
                        #endif
                        cout << "no data from socket "<<*it<< " - closing socket!"<< endl;
                        sock_clients.erase(*it);
                continue;
                         }
 
 
             cout << "Received data: " << buf << endl;
             memset(&buf,0,sizeof(buf));
                    }
              }
             
 
             
      }
      return 0;
}
Добавлено через 10 минут
Цитата Сообщение от Fukki Посмотреть сообщение
Здравствуйте, уважаемые.
Столкнулся с такой вот проблемой. Сделал набросок сервера на неблокирующих сокетах, вродебы все сносно и можно было бы двигаться дальше, но возник ряд проблем при обработке сокетов, закрытых со стороны клиента. Причем, если соединение эмулировалось телнетом, а потом было закрыто - все нормально, сокет нормально закрывается и со стороны сервера, если же клиента эмулировать как делал я (стандартный класс TClientSocket Delphi), и разрывать соединение хотя бы через Client.Active:=False; или
програмно убивать процесс с клиентом, сокет начинает посылать пустые датаграммы, а при попытка его закрыть со стороны сервера приводит к такой ошибке:

_cygtls::handle_exceptions: Exception: STATUS_ACCESS_VIOLATION

Как я понял это просто ошибка доступа к занятому ресурсу, однако опыта в программировании C/C++ Linux у меня почти нет, поэтому решил обратиться на форум. Сорцы сервера внизу, клиент, я думаю смысла скидывать нет - там все прозрачно.


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
#define ENV_POSIX
#include <stdio.h>
#include <iostream>
#include <string>
#include <unistd.h>
#include <set>
#include <algorithm>
 
#ifdef ENV_POSIX
       #include <sys/types.h>
       #include <sys/socket.h>
       #include <netinet/in.h>
       #include <signal.h>
       #include <fcntl.h>
       #include <pthread.h>
#else
       #include <winsock2.h>
#endif
 
using namespace std;
 
void * Socks(void*);
 
 
 
int main (int argc, char **argv)
{
        int id1=1;
        int result;
        pthread_t pSockThread;
        result = pthread_create(&pSockThread, NULL, Socks, &id1);
 
    if(result!=0)
    {
        cout << "thread cr8ing failure!" << endl;
        return EXIT_FAILURE;
    }
    
    while(1)
    {
    //  cout << "main_thread is running!" << endl;
        sleep(1);
    }
}
 
 
 
void * Socks(void* a)
{
      /*variables declaration */
      struct sockaddr_in dst;
 
      #ifdef ENV_POSIX
            int sock, sock_id;
      #else
            SOCKET sock, sock_id;
        WSADATA wsaData;
      #endif
 
      const short int port=5000;
      const short int sock_backlog=200;
      int len = sizeof(struct sockaddr);
      int bytes_read =0;
      char buf[512];
      fd_set sock_readset,sock_errorset;
      set<int> sock_clients;
      set<int>::iterator it;
      timeval sock_timeout;
      sock_timeout.tv_sec = 3;
      sock_timeout.tv_usec = 0;
 
 
 
 
      #ifdef ENV_POSIX
            signal(SIGPIPE, SIG_IGN);
      #else
            cout << "Testing if the WinSock2 version is equal or higher than 2.1...");
            
            if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0)
        {
                  cout << "failed!" << endl;
                  return 1;
            }
            cout << "ok!" << endl;
      #endif
 
      //filling of sockaddr_in structure
      dst.sin_family = AF_INET;
      dst.sin_addr.s_addr = htonl(INADDR_ANY);
      dst.sin_port = htons(port);
 
      //initializing and binding socket
      sock = socket(AF_INET,SOCK_STREAM,0);
      fcntl(sock, F_SETFL, O_NONBLOCK);
      cout << "Waiting for an incoming connection..." << endl;
      bind(sock,(struct sockaddr*)&dst,len);
      listen(sock,sock_backlog);
      int k=0;
 
      while(1)
      {
        cout << "sock_thread is running!-----" << endl;
        int mx=0;
        FD_ZERO(&sock_readset);
        FD_ZERO(&sock_errorset);
        FD_SET(sock, &sock_readset);
        
            for(it = sock_clients.begin(); it != sock_clients.end(); it++)
            {
              FD_SET(*it, &sock_readset);
        }
        mx = max(sock, *max_element(sock_clients.begin(), sock_clients.end()));
 
        //wating for datagrams from clients
 
        if(int errno=select(mx+1, &sock_readset, NULL, &sock_errorset, &sock_timeout) <= 0)
            {
                  cout<<"no data from socks...errno: -"<< errno <<endl;
                  continue;
            }
 
            for(it = sock_clients.begin(); it != sock_clients.end(); it++)
            {
                 if(FD_ISSET(*it, &sock_errorset))
                 {
                      cout<<"error socket det-d"<<endl;
                      close(*it);
                 }
        }
 
            if(FD_ISSET(sock, &sock_readset))
            {
                  //accepting new connection
                  //sock_id = accept(sock,(struct sockaddr*)&dst,&len);
                  //sock_id = accept(sock,NULL,NULL);
                  sock_id = accept(sock, NULL, NULL);
                  if(sock_id < 0)
                  {
                         cout<<"sock accepting error!"<<endl;
 
                  }
          else
          {
                         fcntl(sock_id, F_SETFL, O_NONBLOCK);
                         sock_clients.insert(sock_id);
          }
 
             }
             
             for(it = sock_clients.begin(); it != sock_clients.end(); it++)
             {
                   if(FD_ISSET(*it, &sock_readset))
                   {
                         // data receiving
                         bytes_read = recv(*it, &buf, 1024, 0);
             cout << "inc data "<<*it/sizeof(*it)<<endl;
 
             if(bytes_read == 0)
                     {
                                // closing socket
                                #ifdef ENV_POSIX
                               close(*it);
                        #else
                               closesocket(*it);
                        #endif
                        cout << "no data from socket "<<*it<< " - closing socket!"<< endl;
                        sock_clients.erase(*it);
                continue;
                         }
 
 
             cout << "Received data: " << buf << endl;
             memset(&buf,0,sizeof(buf));
                    }
              }
             
 
             
      }
      return 0;
}

Ах, да, про компилятор: Cygwin/g++
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
20.12.2009, 16:44
Ответы с готовыми решениями:

Непонятная ошибка при закрытии дескриптора файла
1) Непонятная проблема происходит при закрытии дескриптора файла (открытого...

Ошибка При Закрытии Клиента
Никто случаем не сталкивался с ошибкой при закрытии клиента - Не найдена папка...

Ошибка при закрытии сокета "Доступ к ликвидированному объекту невозможен"
Здравтсвуйте, когда закрываю сокет - появляется ошибка: RecieveData Error....

Отследить событие закрытия сокета, при закрытии порта через iptables
Друзья, возникла ситуация, имеется linux-приложение, которое берет из входящей...

Не приходят сообщения от клиента при неблокирующем режиме сокета \winsock
Привет, хочу реализовать простой обмен сообщениями в локальной сети, с...

2
niXman
Эксперт С++
3202 / 1451 / 73
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
20.12.2009, 17:28 #2
Цитата Сообщение от Fukki Посмотреть сообщение
_cygtls::handle_exceptions: Exception: STATUS_ACCESS_VIOLATION
каким образом получено сообщение? если обратить внимание на последние три символа _cygtls, то получиться tls, что означает TLS. какое это имеет отношение к вашему коду, мне не понятно

Далее читаем про select(), и видим, что select() не возвращает код ошибки вам, в случае когда select() вернул -1, нужно проверять значение переменной errno.

еще посмотрите что по этому поводу говорит гугл

Добавлено через 13 минут
Скорее всего, под TLS, подразумевается это Thread+Local+Storage
это более подходит как вариант ошибки.
0
Fukki
0 / 0 / 0
Регистрация: 17.12.2009
Сообщений: 2
20.12.2009, 18:50 #3
Компилю под cygwin, g++ -c etc..далее запускаю в винде через комманд ком, скомпилированный файл подключает к себе cygwin1.dll который эмулирует линукс апи. Далее запускаю несколько клиентов (да хоть и один) и отключаю их. В результате в консоли генерируется код описанной выше ошибки.

Я в курсе про селект и про то, что он возвращает - обработка ошибки через errno не решит проблему, а выводил я значение, возвращаемое селект как отладочное средство, чтобы поподробнее проанализировать ход процесса - называйте как хотите

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

Насчет самой ошибки - гугл молчит как рыба в воде )

Добавлено через 25 минут
Заменил set на простой статический массив - заработало. Возможно шло обращение к несуществующему элементу ряда?? Хотя ошибки в логике я так и не нашел..Если кто нибудь видит - отпишите пожалуйста, хочется разобраться с причиной болезни а не ее симптомами оО

Добавлено через 39 минут
Просто нужно было добавить 0й элемент в ряд, так, чтобы его размер никогда небыл равен 0..всем спасибо, простите за беспокойство
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.12.2009, 18:50

Почему при закрытии клиента закрывается и сервер?
В общем сделал так,чтобы клиент отправлял серверу сообщение,и забирал ответ от...

Как сделать так, чтобы при закрытии клиента закрывался и сервер?
Допустим есть две программы... Одна из них сервер вторая клиент... Первая...

Ошибка при создании сокета
Здравствуйте, при создании сокета происходит ошибка #include sockets.hpp ...


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

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

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