Http Server怪问题(50分)

  • 主题发起人 主题发起人 delphifans_hx
  • 开始时间 开始时间
D

delphifans_hx

Unregistered / Unconfirmed
GUEST, unregistred user!
本人的一个http Client
WSAStartup($101, hxWSAData);
hxSockfd := socket(AF_INET, SOCK_STREAM, 0);
hxSocketAddrIn.sa_family := AF_INET;
hxSocketAddrIn.port := 80;
hxSocketAddrIn.AddrIn.s_add := inet_add('169.192.0.99');
connect(hxSockfd, hxSocketAddrIn, SizeOf(hxSocketAddrIn));
SendBuf := 'GET / /HTTP/1.1'#13#10#13#10;
send(hxSockfd,SendBuf, SizeOf(SendBuf));
recv(hxSockfd,RecvBuf, SizeOf(RecvBuf));
与http Server能连上, 但程序总是阻塞在recv处, 这是为什么呢?
但是同用的代码用TClientSock确能够返回正确的文档
上述代码匆匆敲完,原来的应该没错
 
灌水的哪去了, 烦死了, 高手高手在哪
 
哦。我顶一下。呵。
 
对不起帮不了你,up
 
TCP不是这么简单,Send之后马上就写Recv的,接收要么用消息驱动,要么做个死循环。
下面是消息驱动一个例子,注意它是什么时候用Recv的:

{--------------------------------------------------------------
Simple Example.
Implement TCP(both Client and Server) with Socket API
<zw84611@sina.com>
--------------------------------------------------------------}

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
WinSock, StdCtrls;

const
WM_SOCK = WM_USER + 1; //自定义windows消息
TCP_PORT = 5432; //设定TCP端口号

type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
ListBox1: TListBox;
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
HasConnected, IsServer: boolean;
CliSocket, SvrSocket: integer;
SvrAddrIn, CliAddrIn:TSockAddrIn;
procedure InitSocket;
procedure SendData(Content: string);
procedure ReadData(var Message: TMessage); message WM_SOCK;
procedure SockConnect;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.InitSocket;
var
wsadata: TWsadata;
err{, optval}: integer;
begin

WSAStartup($0101,WSAData);

CliSocket := socket(AF_INET, SOCK_STREAM,IPPROTO_IP);
SvrSocket := socket(AF_INET, SOCK_STREAM,IPPROTO_IP);

if (CliSocket = INVALID_SOCKET)or(SvrSocket = INVALID_SOCKET) then
begin
ShowMessage(inttostr(WSAGetLastError())+' Socket创建失败');
CloseSocket(CliSocket);
exit;
end;

SvrAddrIn.sin_addr.s_addr:= INADDR_ANY;
SvrAddrIn.sin_family := AF_INET;
SvrAddrIn.sin_port :=htons(TCP_PORT);
Bind(SvrSocket, SvrAddrIn, sizeof(SvrAddrIn));

err := Listen(SvrSocket,5);
if err<>0 then ShowMessage('Listen error.');

{optval := 1;
if SetSockopt(SvrSocket,SOL_SOCKET,SO_REUSEADDR,pchar(@optval),sizeof(optval)) = SOCKET_ERROR then
begin
showmessage('SO_REUSEADDR set error.');
end; }

//绑定消息映射
WSAAsyncSelect(SvrSocket, Handle , WM_SOCK, FD_READ or FD_ACCEPT or FD_CONNECT or FD_WRITE or FD_CLOSE);
WSAAsyncSelect(CliSocket, Handle , WM_SOCK, FD_READ or FD_ACCEPT or FD_CONNECT or FD_WRITE or FD_CLOSE);

end;

procedure TForm1.SockConnect;
var
err: integer;
begin

CliAddrIn.sin_addr.s_addr:=inet_addr(PChar(Edit1.Text));
CliAddrIn.sin_family := AF_INET;
CliAddrIn.sin_port :=htons(TCP_PORT);
repeat
err:=connect(CliSocket,CliAddrIn, SizeOf(CliAddrIn));
if err = -1 then
begin
{ if we use WSAAsyncSelect(CliSocket...) in order to receive data at
Client side, here will get error, but it still works. why?
}
//ShowMessage('connect error.');
//ListBox1.Items.Add('connect error.');
HasConnected := false;
break;
end
else
begin
HasConnected := true;
IsServer := false;
end;
until err=0;

end;

procedure TForm1.SendData(Content: string);
begin
Send(CliSocket,Content[1],length(Content),0);
end;

procedure TForm1.ReadData(var Message: TMessage);
var
Event: word;
Buf:array[0..1023] of char;
AddrLen, DataLen: integer;
begin
//
AddrLen := sizeof(SvrAddrIn);
Event := WSAGetSelectEvent(Message.LParam);
//FillChar(SvrAddrIn,AddrLen,0);

case Event of
FD_CONNECT:
begin
ListBox1.Items.Add('connect');
HasConnected := true;
//do nothing?
end;
FD_ACCEPT:
begin
IsServer := true;
HasConnected := true;
ListBox1.Items.Add('accept');
//CloseSocket(CliSocket);
CliSocket := Accept(SvrSocket,@SvrAddrIn,@AddrLen);
ListBox1.Items.Add(format(' port:%d, addr:%s',[SvrAddrIn.sin_port,
inet_ntoa(SvrAddrIn.sin_addr)]));
end;
FD_READ:
begin
DataLen := Recv(CliSocket,Buf,1024,0);
buf[DataLen] := #0;
ListBox1.Items.Add(Buf);
{DataLen := RecvFrom(CliSocket,Buf,sizeof(buf),0,CliAddrIn,AddrLen);
ListBox1.Items.Add(format(' port:%d, addr:%s',[CliAddrIn.sin_port,
inet_ntoa(CliAddrIn.sin_addr)])+strpas(buf));}
end;
FD_WRITE:
begin
ListBox1.Items.Add('write');
end;
FD_OOB:
begin
ListBox1.Items.Add('FD_OOB');
end;
FD_CLOSE:
begin
HasConnected := false;
ListBox1.Items.Add('close');
end;
end; //end of case
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
//202.104.32.230
if (not IsServer)and(not HasConnected) then SockConnect;
SendData('hello, world');
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
CloseSocket(SvrSocket);
CloseSocket(CliSocket);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
HasConnected := false;
IsServer := false;
InitSocket;
end;

end.
 
下面是用死循环实现接收的简单例子,若是图形界面程序,不妨用单独一个线程实现这个循环。

#include <stdio.h>
#include <sys/types.h>
#include <winsock2.h>
#include <memory.h>

#define SERVER_PORT 5432
#define MAX_PENDING 5
#define MAX_LINE 256
void
main()
{
struct sockaddr_in sin;
struct sockaddr_in sout;
char buf[MAX_LINE];
int len;
int lens;
SOCKET s,new_s;
WORD wVersionRequested;
WSADATA wsaData;
int err;

wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
exit(1);
}

/*build address data structure */
memset((char *)&sin,0,sizeof(struct sockaddr));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(SERVER_PORT);
/*setup passive open*/
if ((s=socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET ){
perror("simplex-talk:socket");
exit(1);
}
if ((bind(s, (struct sockaddr *)&sin, sizeof(sin))) != 0){
perror("simplex-talk:bind");
exit(1);
}
if ((listen(s,MAX_PENDING))!=0){
perror("simplex-talk:listen");
exit(1);
}

/*wait for connection, then receive and print text */
while(1){
memcpy((char *)&sout,(char *)&sin,sizeof(struct sockaddr_in));
lens=sizeof(sout);
printf("waiting.../n");
if ((new_s =accept(s,(struct sockaddr *)&sout,&lens)) == INVALID_SOCKET) {
perror("simplex-talk:accept");
exit(1);
}
printf("connection established!/n");
while((len=recv(new_s,buf,sizeof(buf),0))>0){
fputs(buf,stdout);
}
printf("socket closed!/n");
closesocket(new_s);
}
}
 
高手出招,与众不同
 
本人有这么一个想法不知对不对
IP 剥了头就是 TCP和数据
TCP剥了头就是 HTTP和数据

各位大虾不许笑
 
对,TCP对于IP来说就是数据,HTTP对于TCP来说就是数据。

+------+ +-----+ +-----+ +-----+
| HTTP |.. .| SMTP| | TFTP| ... | DHCP|
+------+ +-----+ +-----+ +-----+
| |
+-----+ +-----+
| TCP | | UDP |
+-----+ +-----+
| |
+--------------------------+
| IP & ICMP |
+--------------------------+
|
+------------------------------------------------+
| HardWare Devices and Media Access Protocols |
+------------------------------------------------+

Protocol Relationships
 
zw84611
还有一事不懂, 用TClientSock与HTTP Server接通时通过IP包探测器可以看到
GET / /HTTP/1.0 什么的? 但是
我的Sock代码能只是在recv 处阻塞, 数据“确实”发送出去了
通过netstat也建立了连接, 但为什么看不到 “GET / /HTTP/1.0"
 
要对方有数据发送给你时你才Recv,不是说你自己发完了数据就可以立即Recv的。
 
我是想send成功的数据都应被IP包探测器探测到
 
一般来说你发送了数据,用Sniffer是可以监测到的。
但Sniffer可能会有漏包的现象。要抓到网络上所有的数据包,一个不漏,应该是不可能的,至少用软件不可能。
 
但也不至于每次都不行呀
还有这问题:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1560564
 
1.
connect(hxSockfd, hxSocketAddrIn, SizeOf(hxSocketAddrIn));
=>
if connect(hxSockfd, hxSocketAddrIn, SizeOf(hxSocketAddrIn))= -1
then ShowMessage('connect failed'); //虽然问题不一定出在这里,但还是这样写为好

2.
hxSocketAddrIn.sin_port :=htons(80);
hxSocketAddrIn.AddrIn.s_addr := inet_addr('169.192.0.99');

你肯定你的数据已经发出去了吗?
 
1 指教的是当时是随便写出来得, 以后问问题的时候要注意了
2 SendResult := send(hxSockfd,SendBuf, SizeOf(SendBuf));
因为SendResult=SizeOf(SendBuf) 能否确认数据已经安全传送了
我是这么认为的
 
下面的代码在我这里是可以的,如果还不行,可能是你的Sniffer有问题。

var
WSAData: TWSAData;
FSocket: integer;
SockAddrIn: TSockAddrIn;
err: integer;
Content: string;
begin

WSAStartup($0101,WSAData);

FSocket := socket(PF_INET, SOCK_STREAM,IPPROTO_IP);
SockAddrIn.sin_addr.s_addr:=inet_addr('66.77.9.79'); //www.sina.com
SockAddrIn.sin_family := PF_INET;
SockAddrIn.sin_port :=htons(80);

repeat
err:=connect(FSocket,SockAddrIn, SizeOf(SockAddrIn));
if err = -1 then
begin
ShowMessage('no');
break;
end;
until err=0;

Content := 'GET / /HTTP/1.1'+#13+#10+#13+#10;
Send(FSocket,Content[1],length(Content),0);

end;
 
Thank you !!!
试试, 明天结帐
 
后退
顶部