Вопрос : проблемы при работе сервера по Tcp/ip (Сокеты)

  • Автор темы 4xter
  • Дата начала
4

4xter

Гость
#1
Народ, всем доброго дня=) такая проблемка имеется сервак, к которому подключаются клиенты и который обрабатывает набор данных и отправляет клиенту. Так вот всё отрабатывает правильно и рассчитывает всё здорово, но вот сервак постоянно идет по циклу считывания данных с сокета и причем постоянно. В чем беда не могу понять. Очень надеюсь на вашу помощь.
Вот код серкера. Он получает 2 координаты и возвращает номер четверти, в которой расположена точка:
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">"Сервер"</div></div><div class="sp-body"><div class="sp-content">#include <winsock2.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace std;
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested=MAKEWORD(2,2);
WSAStartup(wVersionRequested,&wsaData);//инициализация WinSock API
//Создание сокета
SOCKET s=socket(AF_INET,SOCK_STREAM,0);
//структура адреса
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(1280);
local.sin_addr.s_addr=htons(INADDR_ANY); //хранится физический IP
int c=bind(s,(struct sockaddr*)&local,sizeof(local));
//помещает сокет в состояние прослушивания
int r=listen(s,5);
while (true)
{
char b1[255];
//b1 = (char*)malloc(strlen(b1) + 1);
char *b2,*Res,*token,*tmp;
int x,y;
b2 = (char*)malloc(strlen(b1) + 1);
//free(b2);
//Структура определяет удаленный адрес
//с которым соединяется сокет
sockaddr_in remote_addr;
int size=sizeof(remote_addr);
SOCKET s2=accept(s,(struct sockaddr*)&remote_addr,&size);
if (s2 == INVALID_SOCKET)
continue;
cout << "Client connected..." << endl;

while(recv(s2,b1,sizeof(b1),0)!=0)
{
int mas[2],x,y,n=0,res=0;
char cset[] = "1234567890-";
//Разбитие на координаты.
tmp=new char[strlen(b1)];
strcpy(tmp,b1);
token = strtok(tmp,";");
while( token != NULL )
{
int fl=0;
char * pch = token;
if (pch[0]=='-')
fl=1;
while(!isdigit(*pch))
{pch++;}
if (pch!=NULL)
{
if (fl==0)
mas[n]=atoi(pch);
else
mas[n]=atoi(pch)*(-1);
n++;
}
token = strtok( NULL,";");
}
x=mas[0];
y=mas[1];
if ((x>0)&&(y>0))
res=1;
else if ((x<0)&& (y>0))
res=2;
else if ((x<0)&& (y<0))
res=3;
else if ((x>0)&& (y<0))
res=4;
_itoa(res,b2,10);
Res=new char[strlen(b2)+1];
strcpy(Res,b2);
Res[strlen(b2)]='\0';
send(s2,Res,sizeof(Res),0);
cout << "Message sent"<< endl;
}
closesocket(s2);
//delete []Res;
//free(b1);
}

WSACleanup();
return 0;
}
 

lazybiz

Well-Known Member
03.11.2010
1 339
0
#4
If no incoming data is available at the socket, the recv call blocks and waits for data to arrive according to the blocking rules defined for WSARecv with the MSG_PARTIAL flag not set unless the socket is nonblocking.

Понимаешь в чем смысл?

Добавлено: Посмотри вот здесь и описание и пример есть:
http://msdn.microsoft.com/en-us/library/ms...28VS.85%29.aspx
 
4

4xter

Гость
#5
как я понял нужно заблокировать сокет, так?
но у меня не получилось закрыть его. я взял closesocket(s2); перенёс в конец цикла.
 

lazybiz

Well-Known Member
03.11.2010
1 339
0
#6
4xter
как я понял нужно заблокировать сокет, так?
Да нет. Я другое имел в виду. Функция recv() не возвращается до тех пор, пока не прочитает что-то из сокета. А когда она что-то прочитывает то возвращаешь значение > 0, т.е. количество прочитанных байт и, соответственно, цикл крутится. Он может прерваться только в том случае если возникнет какая-то ошибка но они, как я понял не возникают. Думаю что все дело в этом. На 100% утверждать конечно не буду, это просто мое предположение.
 
4

4xter

Гость
#7
я как-то вообще запутался...вот кусок кода с другой задачи сервера, которая возвращает слово в обратном порядке:
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">"Сервер2"</div></div><div class="sp-body"><div class="sp-content">while(recv(s2,b1,sizeof(b1),0)!=0)
{
cout << b1 << endl;
int i=strlen(b1);
b2=b1[strlen(b1)];//копируем окончание стоки
i--;
cout <<strlen(b1)<<endl;
for(unsigned j=0;j<=strlen(b1);j++)

{
if (i>=0)
{
b2=b1[j];
i--;
}
}
for(unsigned j=0;j<=strlen(b1);j++)
b1[j]=b2[j];
send(s2,b1,sizeof(b1),0);
cout << "Message sent"<< endl;
}

Подключение к сокету один в один как в предыдущем. Здесь всё Ок и никаких подвисаний не наблюдается. В чём может быть проблема?!
 
4

4xter

Гость
#9
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">"Сервер2 "</div></div><div class="sp-body"><div class="sp-content">#include <winsock2.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace std;
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested=MAKEWORD(2,2);
WSAStartup(wVersionRequested,&wsaData);//инициализация WinSock API
//Создание сокета
SOCKET s=socket(AF_INET,SOCK_STREAM,0);
//структура адреса
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(1280);
local.sin_addr.s_addr=htons(INADDR_ANY); //хранится физический IP
int c=bind(s,(struct sockaddr*)&local,sizeof(local));
//помещает сокет в состояние прослушивания
int r=listen(s,5);
while (true)
{
char b1[128];
//b1 = (char*)malloc(strlen(b1) + 1);
char *b2;
b2 = (char*)malloc(strlen(b1) + 1);
//free(b2);
//Структура определяет удаленный адрес
//с которым соединяется сокет
sockaddr_in remote_addr;
int size=sizeof(remote_addr);
SOCKET s2=accept(s,(struct sockaddr*)&remote_addr,&size);
if (s2 == INVALID_SOCKET)
continue;
cout << "Client connected..." << endl;

while(recv(s2,b1,sizeof(b1),0)!=0)
{
cout << b1 << endl;
int i=strlen(b1);
b2=b1[strlen(b1)];//копируем окончание стоки
i--;
cout <<strlen(b1)<<endl;
for(unsigned j=0;j<=strlen(b1);j++)

{
if (i>=0)
{
b2=b1[j];
i--;
}
}
for(unsigned j=0;j<=strlen(b1);j++)
b1[j]=b2[j];
send(s2,b1,sizeof(b1),0);
cout << "Message sent"<< endl;
}
closesocket(s2);
}

WSACleanup();
return 0;
}
 

lazybiz

Well-Known Member
03.11.2010
1 339
0
#10
Начну пожалуй вот с чего:
C++:
while (true)
{
char b1[128];
//b1 = (char*)malloc(strlen(b1) + 1);
char *b2;
b2 = (char*)malloc(strlen(b1) + 1);
Ты выделяешь память для b2 определяя размер строки b1 которая ни разу не инициализировалась! Т.е. память под b2 может вообще не выделится.

Вот тут тоже какая то странная конструкция:
C++:
int i=strlen(b1);
b2[i]=b1[strlen(b1)];//копируем окончание стоки
Почему бы вторую строку не заменить на: b2=b1; ?

И это я только сразу заметил. Ты бы сначала все ошибки исправил а потом бы мы уже подумали что, почему и как не работает.
 
4

4xter

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

lazybiz

Well-Known Member
03.11.2010
1 339
0
#13
я понимаю что есть ошибки и т.д. но как они влияют на чтение?
Андрей я с Вас фигею.. Возникает ошибка - из-за этого прерывается выполнение recv() а так же прерывается цикл и вы начинаете думать что все работает как надо хотя на самом деле все далеко не так. В общем правьте ошибки.
 
4

4xter

Гость
#14
Начну пожалуй вот с чего:
C++:
while (true)
{
char b1[128];
//b1 = (char*)malloc(strlen(b1) + 1);
char *b2;
b2 = (char*)malloc(strlen(b1) + 1);
Ты выделяешь память для b2 определяя размер строки b1 которая ни разу не инициализировалась! Т.е. память под b2 может вообще не выделится.

Вот тут тоже какая то странная конструкция:
C++:
int i=strlen(b1);
b2[i]=b1[strlen(b1)];//копируем окончание стоки
Почему бы вторую строку не заменить на: b2=b1; ?

И это я только сразу заметил. Ты бы сначала все ошибки исправил а потом бы мы уже подумали что, почему и как не работает.


по порядку что поправил: память под b2 выделяется. переменная i мне нужна как обратный счетчик для формирования строки-зеркала. пусть поменяется b2=b1[strlen(b1)] на b2=b1. я так понял что в коде сервер2 где возникает ошибка в b1? так это? Не судите строго, только начинаю всё это осваивать!=)
 

lazybiz

Well-Known Member
03.11.2010
1 339
0
#16
Сейчас немного занят на работе. Посмотрю ближе к вечеру.

Добавлено: 4xter
В клиенте, который ты мне прислал есть строки подобные вот этой:
C++:
if ( recv( s, b, sizeof( cool.gif, 0 ) != 0 ) {
Думаю там какой-то символ был распознан как смайл.
Не подскажешь что там должно быть? Или как вариант можно прислать еще раз но только в аську.
 

lazybiz

Well-Known Member
03.11.2010
1 339
0
#17
Вот тебе сервер:
C++:
#include <winsock2.h>
#include <iostream.h>

int main( void )
{
WORD		wVersionRequested;
WSADATA		wsaData;

wVersionRequested = MAKEWORD( 2, 2 );
if ( WSAStartup( wVersionRequested, &wsaData ) != 0 ) {
cout << "WSAStartup(): error" << endl;
return 1;
}

SOCKET s = socket( AF_INET, SOCK_STREAM, 0 );

struct sockaddr_in	local;
local.sin_family		= AF_INET;
local.sin_port			= htons( 1280 );
local.sin_addr.s_addr	= htons( INADDR_ANY );

bind( s, (struct sockaddr *)&local, sizeof( local ) );
listen( s, 5 );
while ( 1 ) {
int			size, xy[2], z;
SOCKET		s2;
sockaddr_in	remote_addr;

size = sizeof( remote_addr );

s2 = accept( s, (struct sockaddr *)&remote_addr, &size );
if ( s2 == INVALID_SOCKET ) continue;

cout << "Client connected..." << endl;

while ( recv( s2, (char *)&xy[0], sizeof( int ) * 2, 0 ) != 0 ) {
cout << "Server received: X = " << xy[0] << ", Y = " << xy[1] << endl;
cout.flush();

z = xy[0] * xy[1];	// Schitaem proizvedenie

send( s2, (char *)&z, sizeof( int ), 0 );
}
closesocket( s2 );
}
WSACleanup();
return 0;
}
А вот тебе клиент:
C++:
#include <winsock2.h>
#include <iostream.h>

int main( void )
{
WORD		wVersionRequested;
WSADATA		wsaData;

wVersionRequested = MAKEWORD( 2, 2 );
if ( WSAStartup( wVersionRequested, &wsaData ) != 0 ) {
cout << "WSAStartup(): error" << endl;
return 1;
}

sockaddr_in		peer;
peer.sin_family			= AF_INET;
peer.sin_port			= htons( 1280 );
peer.sin_addr.s_addr	= inet_addr( "127.0.0.1" );

SOCKET s = socket( AF_INET, SOCK_STREAM, 0 );
if ( connect( s, (struct sockaddr *)&peer, sizeof( peer ) ) != 0 ) {
cout << "connect(): error" << endl;
return 1;
}

int		xy[2], z;
cout << "Enter X: ", cin >> xy[0];
cout << "Enter Y: ", cin >> xy[1];

send( s, (char *)&xy, sizeof( int ) * 2, 0 );
if ( recv( s, (char *)&z, sizeof( int ), 0 ) != 0 ) {
cout << "Server returns: " << z << endl;
}

closesocket( s );
WSACleanup();
return 0;
}
Сервер получает два числа от клиента и отправляет их произведение обратно клиенту. Заменишь на свою функцию и будет тебе радость.
 
4

4xter

Гость
#18
спасибо!!! переработал под свою задачу всё заработало=) по аналогии решил и со строками=)