一个很初级的问题,很丢脸~~~ ( 积分: 50 )

  • 主题发起人 主题发起人 masm
  • 开始时间 开始时间
M

masm

Unregistered / Unconfirmed
GUEST, unregistred user!
用惯了控件,现在开始用WinsockAPI写程序了。马上就碰到一个实际问题:
accept()阻塞后,一定要有连接到来才能解除阻塞,然后马上又阻塞了(等待下一个连接)。那么怎么关闭服务端的socket呢?难道accept还在那里阻塞,就可以轻易地Closesocket()了?
 
???
这样的问题还要挂上几天?
看来。丢脸的人越来越多了...[:(]
 
然道你的accept是在主线程里的?那么你的整个应用程序都被阻塞了而不光的套接字了
但你建立侦听的socket可以在主线程中建立,在主线程中关闭,这有什么问题??
我也是最近才研究这东东,我是这么理解的
 
我说的可能不是很清楚。
我的意思是,一旦一个监听sock的accept运行了,那么它就会长期阻塞在这个函数上(一有连接就返回新建的sock套接字,然后立刻又阻塞了),我当然会在另一个线程上去终止这个监听sock。我的问题是:去终止它的时候,他还阻塞在accept那里啊,难道我们终止它,系统会自动让它从accept阻塞状态退出来,然后自行销毁?
 
unit Unit1;

interface

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

type

RECVPARAM = packed record
m_socket: TSocket;
m_handle: THANDLE;
end;

TForm1 = class(TForm)
btn_CloseSocket: TButton;
btn_SendData: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btn_CloseSocketClick(Sender: TObject);
procedure btn_SendDataClick(Sender: TObject);

private
{ Private declarations }
o_Msg: String;
m_socket: TSocket;
pRecvparam: RECVPARAM;
public
{ Public declarations }
function InitSocket(out Msg: String): Boolean;
end;

function RecvProc(lpParameter: Pointer):Integer; stdcall;

var
Form1: TForm1;

implementation

{$R *.dfm}

function RecvProc(lpParameter: Pointer):Integer; stdcall;
var
ilen: Integer;
m_socket: TSocket;
m_handle: THANDLE;
iRecvBytes: Integer;
addrSend: TSockAddrIn;
charBuf: array[0..1000] of char;
AcceptSocket: TSocket;
begin
Result := -1;
m_socket := RECVPARAM(Pointer(lpParameter)^).m_socket;
m_handle := RECVPARAM(Pointer(lpParameter)^).m_handle;
ilen := sizeof(TSockAddrIn);
FillChar(charBuf, sizeof(charBuf), 0);
while (TRUE) do
begin

AcceptSocket := accept(m_socket, @addrSend, @ilen);

if AcceptSocket = SOCKET_ERROR then
begin
MessageBox(m_handle, '接收连接异常', '测试', MB_ICONERROR);
Break;
end;

iRecvBytes := recv(AcceptSocket, charBuf, sizeof(charBuf), 0);

if (iRecvBytes = 0) or (iRecvBytes = SOCKET_ERROR) then
begin
MessageBox(m_handle, '接收数据异常', '测试', MB_ICONERROR);
Break;
end
else
MessageBox(m_handle, charBuf, '测试', MB_OK);

end;

MessageBox(m_handle, '跳出While循环', '测试', MB_OK) ;

Result := 0;
end;

function TForm1.InitSocket(out Msg: String): Boolean;
var
wsaData: TWSADATA;
iResult: Integer;
service: TSockAddrIn;
begin
Result := False;
iResult := WSAStartup(MAKEWORD(2,2), wsaData);
if (iResult <> NO_ERROR) then
begin
Msg := '初始化套接字库失败';
Exit;
end;

m_socket := socket(AF_INET,
SOCK_STREAM,
0);
if (m_socket = INVALID_SOCKET) then
begin
Msg := '创建套接字失败';
Exit;
end;

service.sin_family := AF_INET;
service.sin_port := htons(6010);
service.sin_addr.S_addr := inet_addr('127.0.0.1');

iResult := bind(m_socket, service, sizeof(TSockAddrIn));

if (iResult = SOCKET_ERROR) then
begin
Msg := '绑定套接字失败';
Exit;
end;

iResult := listen(m_socket, 0);

if (iResult = SOCKET_ERROR) then
begin
Msg := '监听套接字失败';
Exit;
end;

Result := True;


end;



procedure TForm1.FormCreate(Sender: TObject);
var
hThread: THANDLE;
lpThreadId: DWORD;
begin
if not InitSocket(o_Msg) then
begin
MessageBox(Handle, PChar(o_Msg), '测试', MB_ICONERROR);
Exit;
end;
pRecvparam.m_socket := m_socket;
pRecvparam.m_handle := handle;
hThread := CreateThread(nil,
0,
@RecvProc,
@pRecvParam,
0,
lpThreadId);
CloseHandle(hThread);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
WSACleanup();
end;

procedure TForm1.btn_CloseSocketClick(Sender: TObject);
begin
closesocket(m_socket);
end;

procedure TForm1.btn_SendDataClick(Sender: TObject);
var
iSendBytes: Integer;
charBuf: array[0..1000] of char;
clientsevice: TSockAddrIn;
ConnectSocket: TSocket;
iLen, iResult: Integer;
begin
iLen := sizeof(TSockAddrIn);
clientsevice.sin_family := AF_INET;
clientsevice.sin_port := htons(6010);
clientsevice.sin_addr.S_addr := inet_addr('127.0.0.1');
ConnectSocket := socket(AF_INET,
SOCK_STREAM,
0);


iResult := connect(ConnectSocket,
clientsevice,
iLen);

if iResult = SOCKET_ERROR then
begin
MessageBox(Handle, '连接套接字异常', '测试', MB_ICONERROR);
Exit;
end;
FillChar(charBuf, sizeof(charBuf), 0);
StrPCopy(charBuf, '测试数据');
iSendBytes := send(ConnectSocket,
charBuf,
sizeof(charBuf),
0);
closesocket(ConnectSocket);
end;

end.


做个最检单的实验
TCP连接的阻塞模式的最简单原型
程序起动后会在下面这一行阻塞等待连接
AcceptSocket := accept(m_socket, @addrSend, @ilen);

当你执行下面这一句时程序从阻塞的地方往下正常执行,且能正常接收数据显示后,又会在上面那一句阻塞
iSendBytes := send(ConnectSocket,
charBuf,
sizeof(charBuf),
0);

OK,现在说明程序的流程没问题,现在来关闭监听的那个套接字,也就是m_socket
closesocket(m_socket);

你会发现下面这一行执行了
if AcceptSocket = SOCKET_ERROR then
begin
MessageBox(m_handle, '接收连接异常', '测试', MB_ICONERROR);
Break;
end;
这就说明你担心的那个问题并不存在
 
谢谢52free的热情解答。非常详细!!
原来,accept()函数能自己抛出异常啊。
 
后退
顶部