![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Помогите с winsocket в WinAPI [D6, D7, WinXP]
chemelin © (2008-01-15 12:30:00)Нужно написать на winsocket без VCL компонентов клиент-сервер которые будут обмениваться данными, помогите пожалуйста, если можно исходник или ссылки на статьи или готовые варианты реализации, буду очень благодарен, малое представление имею о winsocket но не могу реализовать передачу данных!
Сергей М. (2008-01-15 14:05:00) [21]
> Вот смотри
Ну вижу.
И что ?
chemelin (2008-01-15 13:54:00) [22]
> Не надо.
Я видел что я неправильно был здесь написал
recv(sServerListen, buf, 1024, 0);
edit1.Text := sRecvStr;
не хотел снова лепить сообщение.
Вот смотри:
...
var
sRecvBuff, sSendBuff : array [0..255] of char;
ret:Integer;
s:String;
begin
while(true) do
begin
ret := recv(sock, sRecvBuff, 1024, 0);
if (ret = 0) then
Continue
else
if (ret = SOCKET_ERROR) then
begin
MessageBox(0, 'Ошибка получения данных', 'Внимание!!!', 0);
exit;
end;
s:=sRecvBuff;
if s[Length(s)]=#10 then
s:=Copy(s, 1, Length(s)-2);
if s<>'get' then
continue;
sSendBuff:='Command get OK';
ret := send(sock, sSendBuff, sizeof(sSendBuff), 0);
if (ret = SOCKET_ERROR) then
begin
MessageBox(0, 'Ошибка передачи данных', 'Внимание!!!', 0);
break;
end;
end;
CloseSocket(sock);
...
Сергей М. (2008-01-15 13:49:00) [23]
> выложу здесь кодинг
Не надо.
Твоему дурному примеру могут последовать неокрепшие умы твентинпрограммеров)
chemelin (2008-01-15 13:47:00) [24]О, по идее разобрался. Когда сделаю что будет все работать как надо, выложу здесь кодинг, для примера другим!
Сергей М. (2008-01-15 13:47:00) [25]
> для чего она?
Для ожидания запросов на соединение и собственно установки соединения.
> Делаю фот так
Полную ерунду ты делаешь.
Справку по Winsock API ты вообще читал перед тем как лепить код ?
Там же черным по белому написано:
The Windows Sockets recv function receives data from a socket.
int recv (
SOCKET s,
char FAR* buf,
int len,
int flags
);
..
s
[in] A descriptor identifying a connectedsocket.
А ты что толкаешь первым параметром ? Ты туда толкаешь дескриптор слушающегосокета.
Разницу между слушающим сокетом и сокетом, ассоциированным с успешно установленным соединением, осюсяешь ?
Получается что не осюсяешь.
Ну так вперед - читать документацию !
chemelin (2008-01-15 13:28:00) [26]
> Функция accept()
а для чего она?
Делаю фот так:
...
recv(sServerListen, buf, 1024, 0);
edit1.Text := sRecvStr;
...
в чем ошибка?
Сергей М. (2008-01-15 13:17:00) [27]Функция accept() не предназначена для приема данных, для этого существует ф-ция recv()
chemelin (2008-01-15 13:09:00) [28]
> пользуйтесь кнопкой "код" справа от поля ввода
Давно был на этом форуме, забыл за кнопку "код", извиняюсь.
Делал вот так:
...
var
sRecvStr : array [0..255] of char;
...
//Приём нового соединения
sClient :=accept(sServerListen, @sRecvStr, @iSize);
if sClient = INVALID_SOCKET then
begin
TestWinSockError('accept');
end;
edit1.Text := sRecvStr;
...
После приёма данных, в edit1 выводит такой вот символ "|" заместь "get"
Сергей М. (2008-01-15 13:05:00) [29]
> chemelin (15.01.08 12:51) [3]
Что говорит отладчик ?
Григорьев Антон (2008-01-15 12:58:00) [30]Навскидку ошибок не видно, но код нити TCPClientThread не приведён, может, там что не так. Только просьба - пользуйтесь кнопкой "код" справа от поля ввода, а то неоформленный листинг читать тяжело.
chemelin (2008-01-15 12:54:00) [31]Вот кусочек кода с UDP протокола, работает. Но не могу перенести этот код в TCP протокол (в тот код что писал выше)!
//Прослушивание
iSize:=sizeof(clientaddr);
if recvfrom(sServerListen, sRecvStr, 255, 0,
clientaddr, iSize)<>SOCKET_ERROR then
Label1.Caption:=sRecvStr;
chemelin (2008-01-15 12:51:00) [32]
> Что конкретно "не выходит" ?
Не выходит корректно передать драные с клиента на сервер и на оборот, допустим с клиента передаю строку "Hello" и чтобы на сервера она отобразилась в Edit'e, ну и обратная связь! (образный пример)
Сергей М. (2008-01-15 12:44:00) [33]
> не выходит
Что конкретно "не выходит" ?
chemelin (2008-01-15 12:38:00) [34]продолжение вопроса...
Вот у меня есть акая реализация сервер-клмент, подправьте что не так.
TCPClient
procedure TestWinSockError(S:String);
var
iErr:Integer;
sFullErr:String;
begin
sFullErr:='Неизвестная ошибка';
iErr:=WSAGetLastError();
case iErr of
WSANOTINITIALISED: sFullErr:='Нужно сначала вызвать функцию WSASturtup, а потом создавать сокет';
WSAENETDOWN: sFullErr:='Cвязь нарушена, возможные причины - отошёл кабель или отключились от Интернета';
WSAEADDRINUSE: sFullErr:='Указанный адрес уже используется';
WSAEFAULT: sFullErr:='Параметры name и namelen не соответствуют выбранной адресации. Параметр namelen может быть меньше необходимого значения, а name содержать некорректные данные';
WSAEINPROGRESS: sFullErr:='Выполняется операция в блокирующем режиме. Вы уже запустили на выполнение какую-то функцию и нужно дождаться завершения её работы';
WSAEINVAL: sFullErr:='Сокет уже связан с адресом';
WSAENOBUFS: sFullErr:='Недостаточно буферов, слишком много соединений';
WSAENOTSOCK: sFullErr:='Неверный дескриптор сокета';
WSAEISCONN: sFullErr:='Сокет уже подключён';
WSAEMFILE: sFullErr:='Нет больше доступных дескрипторов';
end;
MessageBox(0, PChar('Ошибка в функции '+S+' - '+sFullErr), 'Ошибка', 0);
end;
function LookupName(name:String): TInAddr;
var
HostEnt: PHostEnt;
InAddr: TInAddr;
begin
if name[4]='.' then
InAddr.s_addr := inet_addr(PChar(name))
else
begin
HostEnt := gethostbyname(PChar(name));
FillChar(InAddr, SizeOf(InAddr), 0);
if HostEnt <> nil then
begin
with InAddr, HostEnt^ do
begin
S_un_b.s_b1 := h_addr^[0];
S_un_b.s_b2 := h_addr^[1];
S_un_b.s_b3 := h_addr^[2];
S_un_b.s_b4 := h_addr^[3];
end;
end
end;
Result := InAddr;
end;
procedure TTCPClientForm.btSendClick(Sender: TObject);
var
wData : WSADATA;
sServerListen: TSOCKET;
server_addr : sockaddr_in;
iRet : Integer;
sRecvBuff : array [0..255] of char;
begin
// Загрузка WinSock
if WSAStartup(MAKEWORD(1,1), wData) <> 0 then
begin
MessageBox(0, 'Не могу загрузить WinSock', 'Ошибка', 0);
exit;
end;
// Создание сокета
sServerListen := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if sServerListen = INVALID_SOCKET then
begin
MessageBox(0, 'Ошибка создания сокета', 'Ошибка', 0);
exit;
end;
// Запонение структуры адреса
server_addr.sin_addr.s_addr := htonl(INADDR_ANY);
server_addr.sin_family := AF_INET;
server_addr.sin_port := htons(5050);
server_addr.sin_addr := LookupName(edServer.Text);
if (connect(sServerListen, server_addr, sizeof(server_addr)) = SOCKET_ERROR) then
begin
TestWinSockError('Send');
exit;
end;
sRecvBuff:='get';
iRet := send(sServerListen, sRecvBuff, 3, 0);
if (iRet = SOCKET_ERROR) then
begin
MessageBox(0, 'Ошибка передачи данных', 'Внимание!!!', 0);
exit;
end;
iRet := recv(sServerListen, sRecvBuff, 1024, 0);
if (iRet = SOCKET_ERROR) then
begin
MessageBox(0, 'Ошибка получения данных', 'Внимание!!!', 0);
exit;
end;
edServer.Text:=sRecvBuff;
CloseSocket(sServerListen);
end;
end.
---------------------------------
TCPServer
procedure TestWinSockError(S:String);
var
iErr:Integer;
sFullErr:String;
begin
sFullErr:='Неизвестная ошибка';
iErr:=WSAGetLastError();
case iErr of
WSANOTINITIALISED: sFullErr:='Нужно сначала вызвать функцию WSASturtup, а потом создавать сокет';
WSAENETDOWN: sFullErr:='Cвязь нарушена, возможные причины - отошёл кабель или отключились от Интернета';
WSAEADDRINUSE: sFullErr:='Указанный адрес уже используется';
WSAEFAULT: sFullErr:='Параметры name и namelen не соответствуют выбранной адресации. Параметр namelen может быть меньше необходимого значения, а name содержать некорректные данные';
WSAEINPROGRESS: sFullErr:='Выполняется операция в блокирующем режиме. Вы уже запустили на выполнение какую-то функцию и нужно дождаться завершения её работы';
WSAEINVAL: sFullErr:='Сокет уже связан с адресом';
WSAENOBUFS: sFullErr:='Недостаточно буферов, слишком много соединений';
WSAENOTSOCK: sFullErr:='Неверный дескриптор сокета';
WSAEISCONN: sFullErr:='Сокет уже подключён';
WSAEMFILE: sFullErr:='Нет больше доступных дескрипторов';
end;
MessageBox(0, PChar('Ошибка в функции '+S+' - '+sFullErr), 'Ошибка', 0);
end;
function TestFuncError(iErr:Integer; FuncName:String):Boolean;
begin
Result:=false;
if iErr = SOCKET_ERROR then
begin
TestWinSockError(FuncName);
Result:=true;
end;
end;
procedure TForm1.bStartServerClick(Sender: TObject);
var
wData : WSADATA;
sServerListen, sClient : TSOCKET;
localaddr, clientaddr : sockaddr_in;
iSize : Integer;
s1 : TCPClientThread;
begin
// Загрузка WinSock
if WSAStartup(MAKEWORD(1,1), wData) <> 0 then
begin
MessageBox(0, 'Не могу загрузить WinSock', 'Ошибка', 0);
exit;
end;
// Создание сокета
sServerListen := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if sServerListen = INVALID_SOCKET then
begin
MessageBox(0, 'Ошибка создания сокета', 'Ошибка', 0);
exit;
end;
// Запонение структуры адреса
localaddr.sin_addr.s_addr := htonl(INADDR_ANY);
localaddr.sin_family := AF_INET;
localaddr.sin_port := htons(5050);
//Связывание сокета с локальным адресом
if bind(sServerListen, localaddr, sizeof(localaddr)) = SOCKET_ERROR then
begin
TestWinSockError('Bind');
exit;
end;
//Прослушивание
if TestFuncError(listen(sServerListen, 4), 'Listen') then
exit;
MessageBox(0, 'Сервер запущен', 'Внимание!!!', 0);
while (true) do
begin
iSize := sizeof(clientaddr);
//Приём нового соединения
sClient := accept(sServerListen, @clientaddr, @iSize);
if sClient = INVALID_SOCKET then
begin
TestWinSockError('accept');
break;
end;
// Соединение принято, создаём поток
s1:=TCPClientThread.Create(true);
s1.Sock:=sClient;
s1.Resume;
end;
closesocket(sServerListen);
end;
end.
Пробывал сам сделать не выходит!