1

我一直在为一个朋友和我做一个简单的winsock文件传输来共享文件,而无需每次都上传到mediafire。但我遇到的一个问题是/曾经是(取决于你如何看待我当前的解决方案)我不能' t 在不损坏文件的情况下发送文件。目前我发送/接收的解决方案是:

procedure SenBuf(var buf;count:dword);
var
  a, c: pointer;
  cousend, tmp, left: dword;
begin
  a := @buf;
  cousend := 0;
  left := count;
  repeat
    c := ptr(dword(a) + cousend);
    tmp := Send(hSocket, c^, left, 0);
    inc(cousend, tmp);
    dec(left, tmp);
  until cousend = count;
end;

procedure RecvBuf(var buf;count:dword);
var
  a, c: pointer;
  cousend, tmp, left: dword;
begin
  a := @buf;
  cousend := 0;
  left := count;
  repeat
    c := ptr(dword(a) + cousend);
    tmp := Recv(hSocket, c^, left, 0);
    inc(cousend, tmp);
    dec(left, tmp);
  until cousend = count;
end; 

但是我使用的是 tcp 连接,为什么我需要检查正在发送/接收的字节并重新发送它们?(我知道原因是丢包,因为它在本地主机上完美运行)。

它如何监听连接:

 hServer := Socket(AF_INET,SOCK_STREAM,6);
 sAddr.sin_family      := AF_INET;
 sAddr.sin_port        := htons(wPort);
 sAddr.sin_addr.S_addr := INADDR_ANY;
 Bind(hServer, sAddr, SizeOf(sAddr));
 winsock.Listen(hServer,3);
 while not(Self.Terminated) do begin
   iSize:=SizeOf(cAddr);
   hClient:=Accept(hServer,@cAddr,@iSize);
   if (hClient <> INVALID_SOCKET) then begin
     sleep(50);
     Client := TClient.Create(True);
     Clients.Add(Client);
     with Client do begin
       hHost := inet_ntoa(cAddr.sin_addr);
       Resume();
     end;
 /// incomplete code?

服务器 - 客户端:

    procedure TClient.Execute;
    var
      mode: integer;
      bytBuf: Array[0..255] of Char;
      iRecv: Integer;
    begin
      inherited;
      mode := 0;
      ZeroMemory(@bytbuf, 256);
      ioctlsocket(hSocket, FionBio, mode);
      repeat
        iRecv := Recv(hSocket, bytBuf, 256, 0);
        if (iRecv <= 0) and (iRecv <> EWOULDBLOCK) then 
          break;
        if not(bytbuf[0]=#0) then
          Process(bytBuf);
        ZeroMemory(@bytbuf,256);
      until 1=2;

客户 - 客户:

procedure Start;
var
  mode: integer;
begin
  repeat
    mode := 0;//blocking mode.
    hSocket := Socket(AF_INET, SOCK_STREAM, 6);
    ioctlsocket(hSocket, FionBio, mode);
    Addr.sin_family := AF_INET;
    Addr.sin_port := htons(hport);
    Addr.sin_addr.S_addr := INET_ADDR(pchar(GetIPFromHost(cHost)));
    if (winsock.Connect(hSocket,Addr, SizeOf(Addr)) = 0) then begin
      SenStr('+');
      WaitForServAndProcess;
    end;
  Sleep(20000);
  lping:=GetTickCount;
  until 1 = 2;
end;

有人会告诉我我的错误吗?或者给我一个非常好的winsock教程?(不必被勺子喂)。

4

1 回答 1

2

您正在破坏您的文件数据,因为您在调用 WinSocksend()recv()函数时没有进行任何错误检查,例如:

procedure SenBuf(var buf; count:dword);
var
  a: PByte;
  tmp: Integer;
begin
  a := PByte(@buf);
  while count > 0 do begin
    tmp := send(hSocket, a^, count, 0);
    if tmp = SOCKET_ERROR then begin
      if WSAEWOULDBLOCK = WSAGetLastError() then begin
        // optionally use select() to detect when the socket is writable again...
        Continue;
      end;
      // error!!! Stop sending...
      Exit;
    end;
    inc(a, tmp);
    dec(count, tmp);
  end;
end;

procedure RecvBuf(var buf; count:dword);
var
  a: PByte;
  tmp: Integer;
begin
  a := PByte(@buf);
  while count > 0 do begin
    tmp := recv(hSocket, a^, count, 0);
    if tmp = SOCKET_ERROR then begin
      if WSAEWOULDBLOCK = WSAGetLastError() then begin
        // optionally use select() to detect when the socket is readable again...
        Continue;
      end;
      // error!!! Stop reading...
      Exit;
    end;
    if tmp = 0 then begin
      // disconnected!!! Stop reading...
      Exit;
    end;
    inc(a, tmp);
    dec(count, tmp);
  end;
end; 

.

procedure TClient.Execute;
var
  mode: integer;
  bytBuf: Array[0..255] of Char;
  iRecv: Integer;
begin
  mode := 0;
  ioctlsocket(hSocket, FionBio, mode);
  repeat
    iRecv := recv(hSocket, @bytBuf[0], SizeOf(bytBuf), 0);
    if iRecv <= 0 then begin
      // error or disconnected!!! Stop reading...
      Exit;
    end;
    Process(bytBuf, iRecv);
  until False;
end;
于 2013-04-17T02:31:38.840 回答