如题,先谢谢了

解决方案 »

  1.   

    阻塞模式
    调用方法 listen 开始侦听,最后用一个 while 循环阻塞调用 accept 函数用于等待来自 client 端的连接,如果这个 socket 在主线程(主程序)中运行,这将导致主线程的阻塞。因此,需要创建一个新的线程以运行 socket 服务。server 端与 client 端之间的通信处于同步状态下。 非阻塞模式
    利用 socket 事件 的消息机制, server 端与 client 端之间的通信处于异步状态下。 创建一个socket时,可以指定它是否阻塞。在缺省情况下,Socket函数和WinSock都创建“阻塞”的socket。阻塞socket通过使用select函数或者WSAAsynSelect函数在指定操作下变成非阻塞的。假定应用程序的一个socket s指定了监测FD_READ事件,则在FD_READ事件上变成非阻塞的。当read函数被调用时,不管是否读到数据都马上返回,如果返回一个错误信息表示还在等待,则在等待的数据到达后,消息wMsg发送给窗口hWnd,应用程序处理该消息读取网络数据。
      

  2.   

    //创建一个服务器
    procedure TForm1.Button1Click(Sender: TObject);
    var
    FdSet : TFDSet;
    TimeVal : TTimeVal;
    ErrorCode,AddSize : integer;
    SockAdd_In,Add: TSockAddrIn;
    tm : Longint;
    WSAData : TWSAData;
    FSock,AcceptSock : TSocket;
    begin
    FSock := socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if FSock = SOCKET_ERROR then
    begin
        showmessage(Format('%s;ErrorCode:%d',['套接字创建失败',WSAGetLastError]) );
        Exit;
    end;
    if ckbxB.Checked then
       tm := 1 //非锁定模式
    else tm := 0; //锁定模式
    ioctlsocket(FSock,FIONBIO,tm);SockAdd_In.sin_family := PF_INET;
    SockAdd_In.sin_port := htons(5151);
    SockAdd_In.sin_addr.S_addr := htonl(INADDR_ANY);
    //绑定
    ErrorCode := bind(FSock,SockAdd_In,sizeof(SockAdd_In));
    if ErrorCode = SOCKET_ERROR then
    begin
        showmessage(Format('%s;ErrorCode:%d',['绑定失败:',WSAGetLastError]) );
        Exit;
    end;
    //置为监听模式
    listen(FSock,5);
    //用一个循环来反复判断是否有客户端请求,如果存在请求就创建一个用来接受数据的读取线程
    while true do
    begin
        AddSize := sizeof(Add);
        AcceptSock := accept(FSock,@Add,@AddSize);
        if AcceptSock <> INVALID_SOCKET then
        TSockReadThread.Create(AcceptSock,Memo1);
        Application.ProcessMessages;
    end;
    //上面的是阻塞模式
    如果将循环改成这样,那就是非阻塞模式
    while true do
    begin
        FD_ZERO(FdSet);
        FD_SET(FSock,FdSet);
        TimeVal.tv_sec := 0;
        TimeVal.tv_usec := 500;
        //使用select函数
        if (select(0,@fdSet,nil,nil,@TimeVal) > 0) then
        begin
        AddSize := sizeof(Add);
        AcceptSock := accept(FSock,@Add,@AddSize);
        if AcceptSock <> INVALID_SOCKET then
        TSockReadThread.Create(AcceptSock,Memo1);
        end;
        Application.ProcessMessages; end;
    end;
    随便解释一下 
    timeval = record
        tv_sec: Longint;
        tv_usec: Longint;
    end;
    其中,tv_sec字段以秒为单位指定等待时间;tv_usec字段则以毫秒为单位指定等待时间。若将超时值设置为( 0 , 0),表明select会立即返回,允许应用程序对select操作进行“轮询”。出于对性能方面的考虑,应避免这样的设置。select成功完成后,会在fd_set结构中,返回刚好有未完成的I / O操作的所有套接字句柄的总量。若超过timeval设定的时间,便会返回0。不管由于什么原因,假如select调用失败,都会返回SOCKET_ERROR。用select对套接字进行监视之前,在自己的应用程序中,必须将套接字句柄分配给一个集合,设置好一个或全部读、写以及例外fd_set结构。将一个套接字分配给任何一个集合后,再来调用select,便可知道一个套接字上是否正在发生上述的I / O活动
    另外一种设置为非阻塞模式的方法是通过网络消息和事件通知的方法,即listen(FSock,5);
    //调用WSAAsyncSelect或WSAEventSelect函数的时候,会将套接字自动设为非锁定模式
    if SOCKET_ERROR=WSAAsyncSelect(FSock,Handle,WM_SERVERSOCK,FD_READ or FD_ACCEPT) then
        ShowMessage('WM_SOCKET Error');
    然后在WM_SERVERSOCK这个自定义消息中,去判断是否有客户端发出连接的请求,再创建一个新的 socket与客户端进行通信,原socket则继续监听