winsocket tcp练习一

2021-03-01 15:26

阅读:755

标签:图片   ons   listen   opened   fail   client   startup   art   splay   

server端

技术图片技术图片
unit ServerMainFormUnit;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Win.ScktComp, Winapi.WinSock;

type
  TForm2 = class(TForm)
    ServerSocket1: TServerSocket;
    Memo1: TMemo;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormCreate(Sender: TObject);
var
  wsData: TWSAData;
  ServerSocket, ClientSocket: TSocket;
  ServerAddr, ClientAddr: TSockAddr;
  len: Integer;
  buf: TBytes;
  ErrorCode: Integer;
  L: TLinger;
begin
  WSAStartup($0101, wsData);
  ServerAddr.sin_port := htons(6000);
  ServerAddr.sin_family := PF_INET;
  ServerAddr.sin_addr.S_addr := INADDR_ANY;
  ServerSocket := socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  bind(ServerSocket, ServerAddr, SizeOf(ServerAddr));
  listen(ServerSocket, 10);
  len := SizeOf(ClientAddr);

  ClientSocket := accept(ServerSocket, @ClientAddr, @len);

  buf := BytesOf(jjw);

  if send(ClientSocket, Buf[0], Length(buf), 0) = SOCKET_ERROR then
  begin
    ErrorCode := WSAGetLastError;
    if ErrorCode = WSAEWOULDBLOCK then
      memo1.Lines.Add(WSAEWOULDBLOCK)
    else
      memo1.Lines.Add(ErrorCode.ToString);
  end;

//  shutdown(ClientSocket, 1);   这行代码和下面的代码都能解决 client接收不到数据的问题。

  L.l_onoff := 1;
  L.l_linger := 1;
  setsockopt(
    ClientSocket,
    SOL_SOCKET, SO_LINGER,
    PAnsiChar(@L),
    SizeOf(L)
  );

  if closesocket(ClientSocket) = SOCKET_ERROR then
    memo1.Lines.Add(close error);

  closesocket(ServerSocket);

  WSACleanup;
end;

end.
View Code

client端

技术图片技术图片
unit ClientMainFormUnit;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Win.ScktComp, Winapi.Winsock,
  Vcl.StdCtrls;

type
  TForm2 = class(TForm)
    ClientSocket1: TClientSocket;
    Memo1: TMemo;
    Button1: TButton;
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
    procedure ClientSocket1Write(Sender: TObject; Socket: TCustomWinSocket);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
var
  WSAData: TWsaData;
  ASocket: TSocket;
  addr: TSockAddrIn;

  FDSet: TFDSet;
  buf: array[0..1023] of AnsiChar;
  dataBuf: AnsiString;
  TimeVal: TTimeVal;
  ret: Integer;
begin
  if WSAStartup($0101, WSAData)  0 then
    raise Exception.Create(WSAStartup Error);

  addr.sin_family := AF_INET;
  addr.sin_port := htons(6000);
  addr.sin_addr.S_addr := inet_addr(192.168.1.37);

  ASocket := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);

  if ASocket = INVALID_SOCKET then
    raise Exception.Create(ASocket Error);


  if connect(ASocket, addr, SizeOf(addr)) = SOCKET_ERROR then
    raise Exception.Create(connect Failed.);

  dataBuf := jjwgood;
  send(ASocket, PAnsiChar(dataBuf)^, length(databuf), 0);

  TimeVal.tv_sec := 0;
  TimeVal.tv_usec := 100;

  while not CheckBox1.Checked do
begin
  FD_ZERO(FDSet);
  FD_SET(ASocket, FDSet);

  ret :=  select(0, @FDSet, nil, nil, @TimeVal);
  if ret = SOCKET_ERROR then
  begin
    memo1.Lines.Add(select read error:  + WSAGetLastError.ToString);
    Break;
  end;

  if ret > 0 then
  begin
    if FD_ISSET(ASocket, FDSet) then
    begin
      ret := recv(ASocket, buf, 1024, 0);
      if ret = SOCKET_ERROR then
      begin
        Memo1.Lines.Add(read error);
        Break;
      end
      else if ret = 0 then
      begin
        Memo1.Lines.Add(server closed);
        Break;
      end
      else
        Memo1.Lines.Add(buf);
    end;
  end;

  FD_ZERO(FDSet);
  FD_SET(ASocket, FDSet);

  ret := select(0, nil, @FDSet, nil, @TimeVal);
  if ret = SOCKET_ERROR then
  begin
    memo1.Lines.Add(select write error:  + WSAGetLastError.ToString);
    Break;
  end;

  if ret > 0 then
  begin
    if FD_ISSET(ASocket, FDSet) then
    begin
      if CheckBox2.Checked then
      begin
        dataBuf := test;
        send(ASocket, PAnsiChar(dataBuf)^, length(databuf), 0);
        CheckBox2.Checked := False;
      end;
    end;
  end;

  Application.ProcessMessages;
end;

  closesocket(ASocket);

  WSACleanup;

end;

procedure TForm2.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
begin
  memo1.Lines.Add(read);
end;

procedure TForm2.ClientSocket1Write(Sender: TObject; Socket: TCustomWinSocket);
begin
  memo1.Lines.Add(write);
end;

end.
View Code

 

参考书籍:

windows网络编程 (第二版)

windows socket网络编程

 

补充说明:

server端不调用 shutdown 或 通过 setsockopt 设置 SO_LINGER 时, client 是收不到数据的。

这两个API实际上都起到了 ”延时“ 的效果。相当于在 closesocket 之前 sleep 了一下。

如何优雅的closesocket在《windows socket网络编程》一书中作者有说明。

 

winsocket tcp练习一

标签:图片   ons   listen   opened   fail   client   startup   art   splay   

原文地址:https://www.cnblogs.com/Jiaojiawang/p/14310475.html


评论


亲,登录后才可以留言!