• 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+数据块的长度,这样通过流对象将这些小块数据合并还原成一个完整的数据。

  • 相关阅读:
    JavaCV音视频开发宝典:录制vp8和vp9编码的webm格式视频,以mp4转webm为例
    JavaCV音视频开发宝典:使用JavaCV采集windows系统声音并录制成mp3音频文件(FFmpeg采集windows系统声音)
    JavaCV音视频开发宝典:使用JavaCV和springBoot实现httpflv直播服务,无需流媒体服务,浏览器网页flv.js转封装方式播放rtsp,rtmp和桌面投屏实时画面
    linux用户用户组与ACL
    QUIC协议详解
    技术分享 | 黑盒测试方法论—等价类
    技术分享 | 这些常用测试平台,你们公司在用的是哪些呢?
    干货 | 测试专家(前阿里P8)聊测试职业发展常见瓶颈
    如何做好测试开发?| 破解测试人技术成长常见的 3 种错误思维!
    技术分享 | 黑盒测试方法论—因果图
  • 原文地址:https://www.cnblogs.com/hnxxcxg/p/4539808.html
Copyright © 2020-2023  润新知