zoukankan      html  css  js  c++  java
  • socket发送和接收数据

    1)sendBuf(),sendText(),sendStream()

    几乎所有的通信控件都会提供上面的3个方法。首先看看SendBuf()。

    function TCustomWinSocket.SendBuf(var Buf; Count: Integer): Integer;
    var
    ErrorCode: Integer;
    begin
    Lock;
    try
    Result := 0;
    if not FConnected then Exit;
    Result := send(FSocket, Buf, Count, 0);
    if Result = SOCKET_ERROR then
    begin
    ErrorCode := WSAGetLastError;
    if (ErrorCode <> WSAEWOULDBLOCK) then
    begin
    Error(Self, eeSend, ErrorCode);
    Disconnect(FSocket);
    if ErrorCode <> 0 then
    raise ESocketError.CreateResFmt(@sWindowsSocketError,
    [SysErrorMessage(ErrorCode), ErrorCode, 'send']);
    end;
    end;
    finally
    Unlock;
    end;
    end;

    Result := send(FSocket, Buf, Count, 0); // 发送指定一块指定大小的缓存数据,指定多大就发送多大,但一般不会超过32K的大小,至于太大的数据要如何处理,后面会作出讲解。

    接下来看下sendText()。

    function TCustomWinSocket.SendText(const s: AnsiString): Integer;
    begin
    Result := SendBuf(Pointer(S)^, Length(S) * SizeOf(AnsiChar));
    end;

    原来是调用的sendBuf(),代码就不作解释。

    最后看sendStream()。

    function TCustomWinSocket.SendStream(AStream: TStream): Boolean;
    begin
    Result := False;
    if FSendStream = nil then
    begin
    FSendStream := AStream;
    Result := SendStreamPiece;
    end;
    end;

    调用了SendStreamPiece()。

    function TCustomWinSocket.SendStreamPiece: Boolean;
    var
    Buffer: array[0..4095] of Byte;
    StartPos: Integer;
    AmountInBuf: Integer;
    AmountSent: Integer;
    ErrorCode: Integer;

    procedure DropStream;
    begin
    if FDropAfterSend then Disconnect(FSocket);
    FDropAfterSend := False;
    FSendStream.Free;
    FSendStream := nil;
    end;

    begin
    Lock;
    try
    Result := False;
    if FSendStream <> nil then
    begin
    if (FSocket = INVALID_SOCKET) or (not FConnected) then exit;
    while True do
    begin
    StartPos := FSendStream.Position;
    AmountInBuf := FSendStream.Read(Buffer, SizeOf(Buffer));
    if AmountInBuf > 0 then
    begin
    AmountSent := send(FSocket, Buffer, AmountInBuf, 0);
    if AmountSent = SOCKET_ERROR then
    begin
    ErrorCode := WSAGetLastError;
    if ErrorCode <> WSAEWOULDBLOCK then
    begin
    Error(Self, eeSend, ErrorCode);
    Disconnect(FSocket);
    DropStream;
    if FAsyncStyles <> [] then Abort;
    Break;
    end else
    begin
    FSendStream.Position := StartPos;
    Break;
    end;
    end else if AmountInBuf > AmountSent then
    FSendStream.Position := StartPos + AmountSent
    else if FSendStream.Position = FSendStream.Size then
    begin
    DropStream;
    Break;
    end;
    end else
    begin
    DropStream;
    Break;
    end;
    end;
    Result := True;
    end;
    finally
    Unlock;
    end;
    end;

    大的数据,一般超过32K,就用sendStream()发送,先将数据一次性加载进流对象中,然后每次从流中读取4k大小的数据进一个内存块中,然后通过SOCKET发送这个内存块。

    到这里不免会产生几个疑问。

    大数据为什么要分割成4K的小块分作几次传送?

    一是小块传输增加了数据传输的可靠性,二是无形中增加了服务端的并发能力。

    那么服务端是怎么接收和处理客户端分割传输的数据?

    这里就涉及到"粘包“这个概念了,服务端先创建一个流对象,将每次收到的小块数据依次地写进流对象中,在写之前流的POSITION+数据块的长度,这样通过流对象将这些小块数据合并还原成一个完整的数据。

  • 相关阅读:
    支付
    mui自定义事件带参返回mui.back()
    tomcat+nginx反向代理(实现一个服务器,一个ip共用80端口)
    mui.back()返回刷新功能
    WiFi(网络)调试Android手机
    mysql获取外键, 根据数据库名和表名获取表所对应的所有外键
    @RequestBody接收json字符串,自动将日期字符串转换为java.util.Date
    使用MySQLWorkBench绘制ER图
    jpa动态分页查找
    displaytag的Excel导出实践
  • 原文地址:https://www.cnblogs.com/hnxxcxg/p/4539808.html
Copyright © 2011-2022 走看看