小弟对winsock api不熟,现要通讯一个电表,用vb已实现,代码详见http://topic.csdn.net/u/20100118/10/46b7f270-9077-458c-812b-82ee1260a343.html
在网上查了一段代码,将vb代码改为如下的delphi代码——
function GetDatax(IP:String;startaddress:integer;datacount:integer): TResultArray;
var
  Errorcode,AddSize:Integer;
  ret:Integer;
  WSAData : TWSAData;//一个数据结构,包含winsock的所有属性
  Skc : TSocket;//套接字
  SockAdd_Inc,Add : TSockAddrIn;//套接字的数据结构,包含套接字的所有属性
  order:array[0..11] of char;//命令数组
  FSocket : TSocket;
  FBuf : TResultArray;
  i:Integer;
  tempx:Integer;
begin
  //*********************加载WinSock动态链接库
  Errorcode:=WSAStartup($0101,WSAData);//加载winsock库
  if Errorcode<>0 then//WSAStartup方法,必须通过了才能使用winsock api
    begin
      ShowMessage('加载WinSock动态链接库失败');
      result:=fbuf;
      exit;
    end;
  //*********************在客户端创建一个套接字
  skc := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if skc = SOCKET_ERROR then
    begin
      showmessage('创建套接字失败');
      result:=fbuf;
      Exit;
    end;
  SockAdd_Inc.sin_family := AF_INET;
  SockAdd_Inc.sin_port := htons(502);
  SockAdd_Inc.sin_addr.S_addr := inet_addr(pchar(IP));
  //*********************连接服务器
  tempx:=connect(skc,SockAdd_Inc,sizeof(SockAdd_Inc));
  //*********************发送数据
  order[0] := chr(0); //交换识别号高字节,通常为0
  order[1] := chr(0); //交换识别号低字节,通常为0
  order[2] := chr(0); //协议识别号高字节,为0
  order[3] := chr(0); //协议识别号低字节,为0
  order[4] := chr(0); //以下字节长度高字节
  order[5] := chr(6); //以下字节长度低字节
  order[6] := chr(1); //单元识别号,确省为255,即地址
  order[7] := chr(3); //功能代码
  order[8] := chr(startaddress div 256); //读数据的起始地址高字节
  order[9] := chr(startaddress Mod 256); //读数据的起始地址低字节
  order[10] := chr((datacount * 2) div 256); //显示的参数长度高字节
  order[11] := chr((datacount * 2) Mod 256); //显示的参数长度低字节
  send(SkC,order,12,0);
  //*********************接收数据
  AddSize := sizeof(Add);
  FSocket:=accept(skc,@Add,@AddSize);
  ret := recv(FSocket,fbuf,256,0);
  if ret<=0 then
     begin
      ShowMessage('接收数据失败');
      shutdown(skc,SD_SEND);
      closesocket(skc);
      result:=fbuf;
      exit;
    end;
  //*********************断开连接
  shutdown(skc,SD_SEND);
  closesocket(skc);
  result:=fbuf;
end;但没有收到任何数据,单步调试发现tempx:=connect(skc,SockAdd_Inc,sizeof(SockAdd_Inc));
tempx=0,不知代码错在哪,请高手指教

解决方案 »

  1.   

    tempx := 0 说明连接成功,你的绑定和监听在哪里
      

  2.   

    tempx:=connect(skc,SockAdd_Inc,sizeof(TSockAddrIn));//这里错了,应该是这个结构的大小,而不是你申明的变量大小。
      

  3.   

    用GetLastError看一下是什么错误
      

  4.   

    一样的,
    你的服务器端SOCK是怎么创建的,代码呢?
    给你一段服务器端的代码例子  FSock := socket(PF_INET,SOCK_STREAM , IPPROTO_TCP);
      if FSock = SOCKET_ERROR then
      begin
        showmessage(Format('%s;ErrorCode:%d',['套接字创建失败',WSAGetLastError]) );
        Exit;
      end;
      //根据一个TCheckBox控件的选择情况来决定使用锁定模式还是非锁定模式
      if chkLock.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 := INADDR_ANY;   
      ErrorCode := bind(FSock,SockAdd_In,sizeof(SockAdd_In));
      if ErrorCode = SOCKET_ERROR then
      begin
        showmessage(Format('%s;ErrorCode:%d',['绑定失败:',WSAGetLastError]) );
        Exit;
      end;
      //置为监听模式 backlog参数指定了正在等待连接的最大队列长度
      listen(FSock,5);
      //调用WSAAsyncSelect或WSAEventSelect函数的时候,会将套接字自动设为非锁定模式
      if SOCKET_ERROR=WSAAsyncSelect(FSock,Handle,WM_SERVERSOCK,FD_READ or FD_ACCEPT) then
        ShowMessage('WM_SOCKET Error');
      

  5.   

    把MSDN的帮助给你
    int connect(
      __in          SOCKET s,
      __in          const struct sockaddr* name,
      __in          int namelen
    );
    Parameters

    Descriptor identifying an unconnected socket.name 
    Name of the socket in the sockaddr structure to which the connection should be established.namelen 
    Length of name, in bytes.
    例子#include <stdio.h>
    #include "winsock2.h"void main() {
      //----------------------
      // Initialize Winsock
      WSADATA wsaData;
      int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
      if (iResult != NO_ERROR)
        printf("Error at WSAStartup()\n");  //----------------------
      // Create a SOCKET for connecting to server
      SOCKET ConnectSocket;
      ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
      if (ConnectSocket == INVALID_SOCKET) {
        printf("Error at socket(): %ld\n", WSAGetLastError());
        WSACleanup();
        return;
      }  //----------------------
      // The sockaddr_in structure specifies the address family,
      // IP address, and port of the server to be connected to.
      sockaddr_in clientService; 
      clientService.sin_family = AF_INET;
      clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
      clientService.sin_port = htons( 27015 );  //----------------------
      // Connect to server.
      if ( connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR) {
        printf( "Failed to connect.\n" );
        WSACleanup();
        return;
      }  printf("Connected to server.\n");
      WSACleanup();
      return;
    }
      

  6.   

    从楼主的代码来看,应该TCPClient, TCP是不需要BIND 和LISTEN的,但是那个ACCEPT却是多余的
    connect(skc,SockAdd_Inc,sizeof(SockAdd_Inc)); 
    这句报错的话,你应该去检查的服务端,比如端口是不是一样的,
    另外加个
      try
        connect(skc,SockAdd_Inc,sizeof(SockAdd_Inc)); 
      finally
        ShowMessage(SysErrorMessage(WSAGetLastError));
      end;
      

  7.   

    TCP是不需要BIND 和LISTEN的
    长见识了,但是怎么我把服务器端的端口绑定和监听去掉后,客户端连接不上呢?
      

  8.   

    从楼主的代码来看,应该TCPClient, TCP是不需要BIND 和LISTEN的,
    你看不出是TCP那里少打了个TCPCLIENT,你自己要怎么理解我也没办法
      

  9.   

    解决了,
    将AddSize := sizeof(Add);
    FSocket:=accept(skc,@Add,@AddSize);
    ret := recv(FSocket,fbuf,256,0);
    改为ret := recv(skc,fbuf,256,0);一句就行了
    我是读电表,所以是客户端程序,不需要BIND 和LISTEN的
      

  10.   

    我是下了“深入Delphi6网络编程”这本书仔细研究后解决的,所以推荐一下此书
      

  11.   


    上边我就说了,你的客户端多了个ACCEPT