| 
			| 
					
						| Robinson 
								Интересующийся    Offline | 
								|  | «  : 16-11-2009 13:05 »  |  | 
 
 Здравствуйте! Скачал недавно пример многопоточного клиент серверного приложения, пытаюсь разобраться что к чему и немного модифицировать Ошибка возникает когда подключается больше 2х клиентов: один из клиентов не обменивается данными с сервером, хотя другие работают нормально.... Вот сервер #include "stdafx.h"
 #define MY_PORT 666 // Порт, который слушает сервер
 
 // прототип функции, обслуживающий
 // подключившихся пользователей
 DWORD WINAPI SexToClient(LPVOID thread_info);
 
 // глобальная переменная – количество
 // активных пользователей
 int nclients = 0;
 
 struct ThreadInfo
 {
 SOCKET client_socket;
 HANDLE mutex;
 };
 
 int _tmain(int argc, _TCHAR* argv[])
 {
 using namespace std;
 setlocale(LC_ALL, "Russian");
 
 WSADATA wsadata;
 cout << "TCP SERVER DEMO" << endl;
 
 if (WSAStartup(0x0202, &wsadata))
 {
 // Ошибка!
 cout << "Error WSAStartup " << WSAGetLastError() << endl;
 return -1;
 }
 
 SOCKET mysocket;
 
 if ((mysocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 {
 // Ошибка!
 cout << "Error socket" << WSAGetLastError() << endl;
 WSACleanup();
 // Деиницилизация библиотеки Winsock
 return -1;
 }
 
 sockaddr_in local_addr;
 local_addr.sin_family = AF_INET;
 local_addr.sin_port = htons(MY_PORT);
 local_addr.sin_addr.s_addr = 0;
 
 if (bind(mysocket, (sockaddr *) &local_addr, sizeof(local_addr)))
 {
 // Ошибка
 cout << "Error bind " << WSAGetLastError() << endl;
 closesocket(mysocket);  // закрываем сокет!
 WSACleanup();
 return -1;
 }
 
 if (listen(mysocket, 0x100))
 {
 // Ошибка
 cout << "Error listen " << WSAGetLastError();
 closesocket(mysocket);
 WSACleanup();
 return -1;
 }
 
 cout << "Ожидание подключений" << endl;
 
 //SOCKET client_socket;
 sockaddr_in client_addr;
 
 int client_addr_size = sizeof(client_addr);
 
 //ввожу i для задержки, чтобы успеть запустить несколько клиентов
 int i = 0;
 cin >> i;
 cout << i << endl;
 
 ThreadInfo thd_info;
 thd_info.mutex = CreateMutex(NULL, false, NULL);
 
 while(thd_info.client_socket = accept(mysocket, (sockaddr*) &client_addr, &client_addr_size))
 {
 nclients++;// увеличиваем счетчик подключившихся клиентов
 
 // пытаемся получить имя хоста
 HOSTENT* hst = gethostbyaddr((char*) &client_addr.sin_addr.s_addr, 4, AF_INET);
 
 // вывод сведений о клиенте
 cout << hst->h_name << inet_ntoa(client_addr.sin_addr) << " new connect!" << endl;
 
 DWORD thID;
 HANDLE my_thread = CreateThread(NULL, NULL, SexToClient, &thd_info, NULL, &thID);
 CloseHandle(my_thread);
 }
 
 return 0;
 }
 
 DWORD WINAPI SexToClient(LPVOID thread_info)
 {
 SOCKET my_sock = ((ThreadInfo*) thread_info)->client_socket;
 char buff[64];
 
 // цикл эхо-сервера: прием строки от клиента и возвращение ее клиенту
 int bytes_recv = 0;
 while( (bytes_recv = recv(my_sock, buff, sizeof(buff), 0)) && bytes_recv != SOCKET_ERROR)
 send(my_sock, buff, bytes_recv, 0);
 
 // если мы здесь, то произошел выход из цикла по причине возращения функцией recv ошибки – соединение клиентом разорвано
 if(WaitForSingleObject(((ThreadInfo*) thread_info)->mutex, INFINITE) == WAIT_OBJECT_0)
 {
 --nclients; // уменьшаем счетчик активных клиентов
 std::cout << "-disconnect, clients: " << nclients << std::endl;
 }
 else
 {
 std::cout << "wait" << std::endl;
 }
 
 ReleaseMutex(((ThreadInfo*) thread_info)->mutex);
 
 // закрываем сокет
 closesocket(my_sock);
 return 0;
 }
 
Сначала запускаю сервер, затем несколько клиентов, после чего ввожу i для начала работы сервера. Только 2 клиента принимают и передают инфу, остальные не делают ничего.... Вот клиент #include "stdafx.h"
 #define PORT		666
 #define SERVERADDR	"127.0.0.1"
 #define BUFF_SIZE	64
 
 int main(int argc, char* argv[])
 {
 using namespace std;
 
 char buff[BUFF_SIZE];
 
 cout << "TCP DEMO CLIENT" << endl;
 
 WSADATA wsadata;
 
 if (WSAStartup(0x202, &wsadata))
 {
 cout << "WSAStart error " << WSAGetLastError() << endl;
 return -1;
 }
 
 SOCKET my_sock;
 
 my_sock = socket(AF_INET,SOCK_STREAM,0);
 
 if (my_sock < 0)
 {
 cout << "Socket() error " << WSAGetLastError() << endl;
 return -1;
 }
 
 sockaddr_in dest_addr;
 dest_addr.sin_family = AF_INET;
 dest_addr.sin_port=htons(PORT);
 HOSTENT *hst;
 
 
 if (inet_addr(SERVERADDR) != INADDR_NONE)
 dest_addr.sin_addr.s_addr = inet_addr(SERVERADDR);
 else
 
 if (hst = gethostbyname(SERVERADDR))// hst->h_addr_list содержит не массив адресов, а массив указателей на адреса
 ((unsigned long *)&dest_addr.sin_addr)[0] = ((unsigned long **)hst->h_addr_list)[0][0];
 else
 {
 cout << "Invalid address " << SERVERADDR << endl;
 closesocket(my_sock);
 WSACleanup();
 return -1;
 }
 
 if (connect(my_sock, (sockaddr *)&dest_addr, sizeof(dest_addr)))
 {
 cout << "Connect error " << WSAGetLastError() << endl;
 return -1;
 }
 
 cout << "Connection with " << SERVERADDR << " successful complete" << endl;
 
 
 int nsize;
 
 for(int i = 0; i < 10; i++)
 {
 send(my_sock, "Hallow, server!", sizeof("Hallow, server!"), 0); //передаем строку клиента серверу
 
 if((nsize = recv(my_sock, buff, sizeof(buff) - 1, 0)) == SOCKET_ERROR)
 {
 //некорректный выход
 cout << "Recv error " << WSAGetLastError() << endl;
 closesocket(my_sock);
 WSACleanup();
 return 0;
 }
 
 // выводим на экран
 cout << i << ": " << buff << endl;
 
 Sleep(2000);
 }
 
 cout << "Exit..." << endl;
 closesocket(my_sock);
 WSACleanup();
 return -1;
 }
 
Подскажите, пожалуйста, в чем ошибка и скажите, правильно ли я организовал блокировку в сервере |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| RXL | 
								|  | « Ответ #1 : 16-11-2009 13:09 »  |  | 
 
 Robinson, в многопоточном приложении при работе с общими объектами необходимо пользоваться средствами синхронизации. |  
						| 
								|  |  
								|  |  Записан | 
 
 ... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С. |  |  | 
	| 
			| 
					
						| Robinson 
								Интересующийся    Offline | 
								|  | « Ответ #2 : 16-11-2009 15:03 »  |  | 
 
 как я понимаю общий объект у меня это глобальная переменная nclients доступ к ней в каждом потоке я синхронизирую так if(WaitForSingleObject(((ThreadInfo*) thread_info)->mutex, INFINITE) == WAIT_OBJECT_0){
 --nclients; // уменьшаем счетчик активных клиентов
 std::cout << "-disconnect, clients: " << nclients << std::endl;
 }
 else
 {
 std::cout << "wait" << std::endl;
 }
 
 ReleaseMutex(((ThreadInfo*) thread_info)->mutex);
 
только ошибка возникает не здесь, а , ИМХО, когда пытаются одновременно подключиться несколько клиентов... что именно мне нужно синхронизировать? |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #3 : 16-11-2009 15:18 »  |  | 
 
 во всё не всматривался , но в глаза бросилось вот что: HANDLE my_thread = CreateThread(NULL, NULL, SexToClient, &thd_info, NULL, &thID);CloseHandle(my_thread);
 
не знаю как другие, а я так с потоками не поступал никогда, да и мсдн пишет  The thread object remains in the system until the thread has terminated and all handles to it have been closed through a call to CloseHandle.
 то есть поток мог прерваться, даже не начавшись, а скорее всего - на половине. А, может, и успевал отрабатывать. для выхода из потока лучше использовать естественное его завершение DWORD WINAPI SexToClient(LPVOID thread_info){
 ...
 return 0;
 }
 
 |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Robinson 
								Интересующийся    Offline | 
								|  | « Ответ #4 : 16-11-2009 16:20 »  |  | 
 
 убрал CloseHandle(my_thread); - ничего не изменилось, но все равно спасибо за замечание... |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| sss 
								Специалист    Offline | 
								|  | « Ответ #5 : 17-11-2009 02:05 »  |  | 
 
 Robinson, в клиенте добавь проверку выполнения send вот в этом месте:    send(my_sock, "Hallow, server!", sizeof("Hallow, server!"), 0); //передаем строку клиента серверу
Что нибудь проявится. Может быть данные не были отправлены из-за ошибки, например, WSAENOBUFS    ... P.S.: Интересное применение sizeof, не правда ли! |  
						| 
								|  |  
								| « Последнее редактирование: 17-11-2009 02:12 от sss » |  Записан | 
 
  while (8==8)  |  |  | 
	| 
			| 
					
						| Domenik 
								Гость
 | 
								|  | « Ответ #6 : 17-11-2009 04:30 »  |  | 
 
 HANDLE my_thread = CreateThread(NULL, NULL, SexToClient, &thd_info, NULL, &thID);CloseHandle(my_thread);
 
Вполне приемле мая строка. CloseHandle(my_thread); означает лишь то, что с указателем на данный поток вы работать не буде те, а не то,  что поток уничтожается, если правильно описан поток, то возможно управления им из родительского потока и не потребуется. Сам,  когда писал чат сервер,  делал аналогично, прекрасно все ра ботало.P.S . возможно Алексей1153++ прав, я лишь говорю о собственном опыте. |  
						| 
								|  |  
								| « Последнее редактирование: 17-11-2009 06:11 от Sel » |  Записан | 
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #7 : 17-11-2009 04:57 »  |  | 
 
 sss, а лучше так   const char* p="Hallow, server!";send(my_sock, p, ::strlen(p)+1, 0); //передаем строку клиента серверу
 
Domenik, дело в том, что я не проверял, что будет, если так закрыть хендл только что запущенного потока    Более того, я никогда его, хендл, не сохранял, то есть тупо так: ::CreateThread(NULL, NULL, SexToClient, &thd_info, NULL, &thID); и всё. Ну и обеспечиваю естественный выход из процедуры потока всегда. Пока что всё работает нормально   А сеть я пишу в MFC на полюбившемся CAsyncSocket - он такой ручной, чертяко )) --------------- Эй, знатоки, разъясните )) |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| sss 
								Специалист    Offline | 
								|  | « Ответ #8 : 17-11-2009 05:15 »  |  | 
 
 Алексей1153++, а лучше так    #define HELLOW_TEXT_409      TEXT("Hallow, server!")#define HELLOW_TEXT_419      TEXT("Прывет, сервер!")
 #define HELLOW_TEXT          HELLOW_TEXT_409
 
 HRESULT          hr;
 ExceptionReport  eReport;
 size_t           stCbLen;
 try
 {
 if ( FAILED( hr = ::StringCbLength( HELLOW_TEXT, BUFF_SIZE, &stCbLen)))
 throw new __EComError( hr);
 
 if ( SOCKET_ERROR == ::send( my_sock, HELLOW_TEXT, stCbLen, 0))
 throw new __ESystemError( ::WSAGetLastError());
 }
 catch( EExcept* e)
 {
 std::cout << "client exception report: " << e->GetReport( eReport)  << std::endl;
 e->Release();
 }
 }
 
Я только так работаю со строками, уже года 2.... |  
						| 
								|  |  
								| « Последнее редактирование: 18-11-2009 04:08 от sss » |  Записан | 
 
  while (8==8)  |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #9 : 17-11-2009 05:46 »  |  | 
 
 дефайны (да и то они не всегда нужны) пригодятся, когда текст много где использовался, а тут достаточно и одном месте ) Незачем загромождать, когда не нужно. |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Domenik 
								Гость
 | 
								|  | « Ответ #10 : 17-11-2009 06:37 »  |  | 
 
  sss  
 используй char, так намного удобней, а в дефайнах и так много всякой нечисти, и без текстовых строк).
 
 П.С. Прошу прощения за мой английский =)
 
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #11 : 17-11-2009 06:44 »  |  | 
 
 используй char, так намного удобней
 чем же ? Поясни на примере |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Domenik 
								Гость
 | 
								|  | « Ответ #12 : 17-11-2009 07:03 »  |  | 
 
 ...char* p="<<Здесь буфер большой длинны>>";
 send(my_sock, p, ::strlen(p)+1, 0); //передаем строку клиента серверу
 delete[] p;
 ...
 
Плюс в том, что можно не плодить в памяти множество буферов, а создавать их, когда они понадобились, а когда они больше не нужны, их можно удалить. Во-вторых,  define служит как вы сами и говорили не для этого, а для того, чтобы определить там константы, которые впоследствии будут использоваться множество раз. В-третьих, мне удобней использовать char, не знаю точно почему, исторически так сложилось наверно… |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| sss 
								Специалист    Offline | 
								|  | « Ответ #13 : 17-11-2009 08:16 »  |  | 
 
 Domenik, и чё после delete[] p? Исключений не бывает? 
 P.S.: И кстати, с чего ты взял что я использую char а не wchar_t?
 
 P.P.S.: Я вообще хотел привлечь внимание не к define, а к StringCbLength!!!
 |  
						| 
								|  |  
								| « Последнее редактирование: 17-11-2009 08:19 от sss » |  Записан | 
 
  while (8==8)  |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #14 : 17-11-2009 09:28 »  |  | 
 
 Domenik, ты вообще то не про char* , а про char говорил - это же разное )) а тут char* p="<<Здесь буфер большой длинны>>";
 во первых, строка КОНСТАНТНАЯ, а не буфер (даст ли компилятор так сделать ?) во вторых - а 256 длину максимум не хочешь ? ) Тоже компилятор скажет. в самых третьих , если где то используешь две одинаковые константные строки, то это не будут буферы, это будут указатели на одну и ту же строку. const char* p1="одинаковый текст"; const char* p2="одинаковый текст"; const char* p3="одинаковый текст"; с delete - это вообще цирк...   sss. надо было явно указать, что подчёркивал, а то мы щас устроим ))) |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Domenik 
								Гость
 | 
								|  | « Ответ #15 : 17-11-2009 10:58 »  |  | 
 
 Алексей1153++ char* ttt	=	"1234567 <всего 1680 чаров + ZT> 567890";
 delete[] ttt;
 
 
Лень считать, сколько символов, но 100% больше 256.. специально проверил только что(ибо в моей памяти всплывает цифра 65536) По поводу delete[]... Когда создается массив, в памяти выделяется область, под этот массив, функция delete[] освобождает эту область и позволяет использовать ее для других нужд.Предлогаю закончить обсуждение темы про char... |  
						| 
								|  |  
								| « Последнее редактирование: 17-11-2009 12:32 от Алексей1153++ » |  Записан | 
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #16 :  17-11-2009 11:17 »   |  | 
 
 а я предлагаю продолжить, уж больно интересный случай, клинический прямо. ))) 1681 символов. Мне тоже лень считать, за меня это студия делает char* ttt ="123";delete[] ttt;
 
 По поводу delete[]...
 
 Когда создается массив, в памяти выделяется область, под этот массив, функция delete[] освобождает эту область и позволяет использовать ее для других нужд.
 
1) где оператор new ? 2) писал ли ты таким образом прогрмаммы и со скольких школ тебя за это уволили ? |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Domenik 
								Гость
 | 
								|  | « Ответ #17 : 17-11-2009 12:16 »  |  | 
 
 1) оператор new в перспективе, в отдаленном светлом будущем...2) так не пишу.
 
 естественно память должна выделяться оператором new если вы об этом.
 
 
 понял я уже что накосячил....
 
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Robinson 
								Интересующийся    Offline | 
								|  | « Ответ #18 : 17-11-2009 22:19 »  |  | 
 
 ещё раз спасибо, но опять ничего не изменилось....может быть такой случай высосан из пальца и нет смысла так тестить? P.S. HANDLE my_thread = CreateThread(NULL, NULL, SexToClient, &thd_info, NULL, &thID);
 Sleep(1); // Наверно ламерское решение, но работает...
 
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| sss 
								Специалист    Offline | 
								|  | « Ответ #19 : 18-11-2009 03:55 »  |  | 
 
 Robinson, ошибок send не возникает? Моё мнение - дело не в создании потока.
 Алексей1153++, злой ты...
 |  
						| 
								|  |  
								|  |  Записан | 
 
  while (8==8)  |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #20 : 18-11-2009 04:06 »  |  | 
 
 sss, конечно злой ))) Невысыпаюсь. А так я добрый, чорный и пушыстый. Robinson, можно в поток передать указатель на синхронизируюший объект (событие,мутекс) а после запуска потока ждать этого события или блокировки мутекса. тогда всё будет точно   Ну это я не к тому, что это решение твоей проблемы с сокетом, а к вопросу о синхронизации |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| zubr 
								Гость
 | 
								|  | « Ответ #21 : 18-11-2009 04:47 »  |  | 
 
 Алексей1153++, CloseHandle надо делать не для удаления потока (CloseHandle не удаляет поток), а для удаления хендла потока (некоего числа выделяемого системой), чтобы не мусорить систему. Представь, если какая нибудь программа (или множество программ) в системе каждую секунду создают n-ое колличество потоков, хендлы которых не удаляются, через какое то время работы этих программ системе может не хватать 32 бит под генерацию нового хендла. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #22 : 18-11-2009 04:51 »  |  | 
 
 zubr, хорошо, буду знать ) |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| Антон (LogRus) | 
								|  | « Ответ #23 : 18-11-2009 05:11 »  |  | 
 
 Robinson, добавь вывод в консоль: 1. сразу после получения нового соединения 2. внутри функции потока, при входе. 3. в цикле, можно выводить размер полученных данных и сами данные, особенно, если клиентов научить передавать ID процесса и что бы они его писали в консоль (пригодится при анализе) 	while( (bytes_recv = recv(my_sock, buff, sizeof(buff), 0)) && bytes_recv != SOCKET_ERROR)send(my_sock, buff, bytes_recv, 0);
 
в начале каждого сообщения в консоль пиши ThreadID проведи испытания для случая со Sleep и без него. HANDLE my_thread = CreateThread(NULL, NULL, SexToClient, &thd_info, NULL, &thID);
 Sleep(1); // Наверно ламерское решение, но работает...
 
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Странно всё это.... |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #24 : 18-11-2009 05:51 »  |  | 
 
 я понял, почему у менябез закрывания хендла всё работает - я же вызываю MFC-шную версию запуска::AfxBeginThread
 
 а там завёрнуто создание класса потока CWinThread, а по выходу из потока (return 0) вызывается AfxEndThread, которая всё автоматом освобождает. А я как-то не задумывался над этим раньше - я полагал, что эта функция тупо вызывает CreateThread, а там, оказывается, они наворотили огородище
 
 Попробовал также и CreateThread + CloseHandle - всё нормально, поток остаётся, хендл убивается (счётчики в диспетчере тоже всё подтвердили )) )
 |  
						| 
								|  |  
								| « Последнее редактирование: 18-11-2009 05:53 от Алексей1153++ » |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| sss 
								Специалист    Offline | 
								|  | « Ответ #25 : 18-11-2009 09:13 »  |  | 
 
 LogRus, sizeof(buff) не смущает? 
 Здесь случай ооочень тяжелый. Здесь не об работе потоков надо речь вести, а об знании языка и используемого API...
 |  
						| 
								|  |  
								| « Последнее редактирование: 18-11-2009 09:17 от sss » |  Записан | 
 
  while (8==8)  |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #26 : 18-11-2009 09:16 »  |  | 
 
 если так то всё правильно,  а вот ежели динамический массив - то тогда косяк ) |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| sss 
								Специалист    Offline | 
								|  | « Ответ #27 : 18-11-2009 09:20 »  |  | 
 
 Алексей1153++, что там recv ожидает на входе? 
 int recv( SOCKET s, char FAR* buf,  int len,  int flags);
 
 Так что там всегда sizeof(char*)...
 
 в общем пример всегда посылает 'Hall', не законченный нулем. Потом это дело с удовольствием выводится на cout.... Интересно, откуда он (поток) знает, что буфер закончился?
 |  
						| 
								|  |  
								| « Последнее редактирование: 18-11-2009 09:24 от sss » |  Записан | 
 
  while (8==8)  |  |  | 
	| 
			| 
					
						| Алексей++ 
								глобальный и пушистыйГлобальный модератор    Offline 
								Сообщений: 13
								
								
								
								
								
							 | 
								|  | « Ответ #28 : 18-11-2009 09:22 »  |  | 
 
 эээ... The recv function receives data from a connected or bound socket.
 int recv(
 SOCKET s,
 char* buf,
 int len,
 int flags
 );
 
 Parameters
 s
 [in] Descriptor identifying a connected socket.
 buf
 [out] Buffer for the incoming data.
 len
 [in] Length of buf, in bytes
 flags
 [in] Flag specifying the way in which the call is made.
 
len - Length of buf, in bytes  |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| sss 
								Специалист    Offline | 
								|  | « Ответ #29 : 18-11-2009 09:25 »  |  | 
 
 Ну я про именно этот пример... Там однозначно buff имеет тип char* |  
						| 
								|  |  
								|  |  Записан | 
 
  while (8==8)  |  |  | 
	|  |