要实现一个TFTP SERVER, 我建立一个DLG 项目, 加一个BUTTON , 点击后创建一个线程, 线程函数就是建立一个SOCKET 并BIND在69 端口上,  然后就在那儿recvfrom(),启动后用TFTP CLIENT对他发送或读取数据, 但SERVER返回值一直都是-1 , 根本就没收到CLIENT的请求, WHY? 

解决方案 »

  1.   

    正常情况下recvfrom应该堵赛直到有client发送的sendto数据报到来,刻检查是不是这样,并检查recvfrom的返回值
      

  2.   

    使用WSAGetLastError看看错误信息是什么
      

  3.   

    用套接口实现UDP协议的网络通信大连开发区捷通电脑技术
    有限公司(116600)王淼
    ----套接字是支持TCP/IP协议的网络通信的基本操作单元。可以将套接字看做不同主机间的进程进行双向通信的端点。在网络编程中最常用的方案便是客户机/服务器模型。本文主要讨论C/S模型下用套接口实现UDP协议的网络通信。利用Socket而自定义了CSockAddr类(与地址有关的机能都封装在这里)和CBlockingSocket类(里面封装了Socket),通过实践证明,通过使用这两个自定义类,可使应用程序非常简练、易读。一、Socket类型
    ----根据传输数据类型的不同,套接字可分为面向连接的字节流套接字(streamsockets)和无连接的数据报套接字(datagramsockets)两种类型。
    ----1.字节流套接字----字节流不按记录定界,在TCP/IP协议簇中对应TCP协议,即传输控制协议。它是一个提供给用户进程可靠的全双工的面向连接的协议,大多数Internet应用程序如ftp、telnet使用TCP协议。----2.数据报套接字----数据报对应记录型数据流,在TCP/IP协议簇中对应UDP协议,即用户数据报协议(UserDatagramProtocol)。由于不建立连接,数据报协议比连接协议快。但不能保证所有数据都准确有序地到达目的地,不保证顺序性、可靠性和无重复性。它是无连接的服务,以独立的信包进行传输,通信端点使用UDP对应的Internet地址。双方不需互连,按固定的最大长度进行传输,因而适用于单个报文传输。二、数据报套接字的工作过程
    ----不论何种套接字编程,均采用客户机/服务器方式,数据报套分别生成服务进程和客户进程,在通信前必须创建各自的套接字以建立连接,然后对相应的套接字进行“读”“写”操作,实现信息的交换。如下图无连接协议的Socket编程模型。
    服务器 客户机
    socket() socket()
      |   |
    bind() bind()
      |   |
    recvfrom()   |
      |<--------------------sendto()
    处理服务请求   |
      |
    sendto()--------------->recvfrom()
      |   |
    close() close()三、编程示例
    ----利用SOCKET而自定义了CSockAddr类(与地址有关的机能都封装在里面)和CBlockingSocket类(里面封装了SOCKET),然后用VC++生成两个对话框工程,一个是服务器程序SV,另一个是客户端程序CL。实践证明,通过使用这两个自定义类,可使应用程序非常简练、易读。
    ----以下是CSockAddr类和CBlockingSocket类这两个类的源程序。服务器程序SV和客户端程序CL只列出了相关的部分。/***bsock.cpp:
    **BlockSocketclass*/
    //Socket地址类只跟AF_INET对应
    //与地址有关的机能都在这里封装了。
    typedefSOCKADDR*LPSOCKADDR;
    classCSockAddr{
     SOCKADDR_INm_SockAddrIN;
    public:
     CSockAddr(LPCSTRaddress=NULL,intport=0,
    intfamily=AF_INET);//构造CSockAddr
    //向LPSOCKADDR变换的运算
     operatorLPSOCKADDR(void){return
    (LPSOCKADDR)&m_SockAddrIN;}
     intGetSize(void){returnsizeof(m_SockAddrIN);}
    //IP情报的大小
     BOOLIsIPAddress(LPCSTRaddress);
    //IP地址的检查nnn.nnn.nnn.nnn
    (n是[0-9])的形式检查
     //IP地址的设定
     voidSetIPAddrees(LPCSTRddress)
    {m_SockAddrIN.sin_addr.s_addr=::inet_addr(address);}
     //由主机名的IP地址的设定
     BOOLSetIPAddressByHost(LPCSTRhostname)
     {
     structhostent*host=gethostbyname(hostname);
     if(host==NULL){
     TRACE(“SERVER%s没有找到code=
    %d",hostname,WSAGetLastError());
     returnFALSE;
     }
     m_SockAddrIN.sin_addr.s_addr=*(int*)host->h_addr;
     returnTRUE;
    }
    //IP地址的文字的取得
    CStringGetIPString(void)
    {
    CStringstr;
    str.Format(“%d.%d.%d.%d",
    m_SockAddrIN.sin_addr.S_un.S_un_b.s_b1,
    m_SockAddrIN.sin_addr.S_un.S_un_b.s_b2,
    m_SockAddrIN.sin_addr.S_un.S_un_b.s_b3,
    m_SockAddrIN.sin_addr.S_un.S_un_b.s_b4
    );
    returnstr;
    }
     intGetPort(void){returnntohs(m_SockAddrIN.
    sin_port);}//PORT的取得
     voidDump(void)//DEBUG用
    {
     TRACE(“famiry=%d\n",m_SockAddrIN.
    sin_family);
     TRACE(“port=%d\n",ntohs(m_SockAddrIN.
    sin_port));
     TRACE(“addr=%s\n",GetIPString());
    }
    };
    (未完)
      

  4.   

    //CBlockingSocketclass
    classCBlockingSocket{
    protected:
    public:
    intm_BufferPointer;//1文字接受BUFFER
    intm_BufferLength;
    BYTEm_RecvBuffer[1024];
    intm_ReceiveTimeout;//收数据TIMEOUT
    //SOCKETHANDLE
    SOCKETm_hSocket;
    CBlockingSocket(void)//构造CBlockingSocket
    {
    m_ReceiveTimeout=INFINITE;
    m_hSocket=INVALID_SOCKET;
    m_BufferPointer=0;
    m_BufferLength=0;
    }
    ~CBlockingSocket(void){}//DESTORY
    //SCOKET的作成
     BOOLSocket(intnSocketType=SOCK_STREAM,
    intnProtocolType=IPPROTO_IP,intnAddressFormat=PF_INET);
     BOOLBind(CSockAddr&addr)//SCOKET的绑定
    {
    if(bind(m_hSocket,addr,addr.GetSize())==
    SOCKET_ERROR){
    TRACE(“bind()error\n");
    returnFALSE;
    }else{
    returnTRUE;
    }
    }
    voidAttach(SOCKETsock){m_hSocket=sock;}
    //SCOKET的HANDLE设定
    voidDetach(void){m_hSocket=INVALID_
    SOCKET;}//SCOKET的HANDLE切断
    virtualvoidClose();//SCOKET的CLOSE
    BOOLListen(intnConnectionBacklog=5);//连接监听
    virtualBOOLAccept(CBlockingSocket&
    rConnectedSocketCSockAddr*lpSockAddr=NULL);
    //连接认可
    BOOLConnect(CSockAddr&addr)//请求连接
    {
    if(connect(m_hSocket,addr,addr.GetSize())==
    SOCKET_ERROR){
    returnFALSE;
    }else{
    returnTRUE;
    }
    }
    //接受数据TIMEOUT的设定
    virtualvoidSetReceiveTimeout(intmsec)
    {m_ReceiveTimeout=msec;}
    virtualintReceive(void*
    lpBuf,intnBufLen,intnFlags=0);//数据接收
    virtualintReceive(void);//一个文字接受
    virtualintSend(constvoid*lpBuf,intnBufLen,
    intnFlags=0);//送信
    //数据块送信
    virtualintSendTo(constvoid*lpBuf,
    intnBufLen,CSockAddr&addr,intnFlags=0)
    {
    returnsendto(m_hSocket,(constchar*)
    lpBuf,nBufLen,nFlags,addr,addr.GetSize());
    }
    //数据块接收
    virtualintReceiveFrom(void*lpBuf,intnBufLen,
    CSockAddr&addr,intnFlags=0)
    {
    SOCKADDR*sa=addr;
    intlen=addr.GetSize();
    intret=recvfrom(m_hSocket,(char*)lpBuf,
    nBufLen,nFlags,sa,&len);
    returnret;
    }
    };//endoffile
    /***bsock.cpp:
    **BlockSocketclass*/
    #include“stdafx.h"
    #include“winsock.h"
    #include“bsock.h"
    //SOCKADDR_IN构造体的作成
    CSockAddr::CSockAddr(LPCSTRaddress,intport,intfamily)
    {
    SOCKADDR_IN&sockAddr=m_SockAddrIN;
    memset(&sockAddr,0,sizeof(sockAddr));
    sockAddr.sin_family=AF_INET;
    //
    if(address==NULL){
    sockAddr.sin_addr.s_addr=htonl(INADDR_ANY);
    }else{
    //IP的数字或文字的判断
    BOOLipaddr=IsIPAddress(address);
    if(!ipaddr){
    SetIPAddressByHost(address);
    }else{
    SetIPAddrees(address);
    }
    }
    sockAddr.sin_port=htons((u_short)port);
    }
    //IP地址的检查//nnn.nnn.nnn.nnn
    (n是[0-9])的形式检查
    BOOLCSockAddr::IsIPAddress(LPCSTRaddress)
    {
    BOOLname=FALSE;
    for(inti=0;address[i];i++){
    if((!isdigit(address[i]))&&address[i]!=.'){
    name=TRUE;
    }
    }
    return(!name);
    }//SOCKET作成
    BOOLCBlockingSocket::Socket(intnSocketType,
    intnProtocolType,intnAddressFormat)
    {
    m_hSocket=socket(nAddressFormat,
    nSocketType,nProtocolType);
    if(m_hSocket!=INVALID_SOCKET)
    returnTRUE;
    TRACE(“Socket()Error\n");
    returnFALSE;
    }
    //SOCKET关闭
    voidCBlockingSocket::Close()
    {if(m_hSocket!=INVALID_SOCKET){
    closesocket(m_hSocket);
    m_hSocket=INVALID_SOCKET;
    }
    }
    //连接认可
    BOOLCBlockingSocket::Accept(CBlockingSocket
    &rConnectedSocket,CSockAddr*lpSockAddr)
    {
    SOCKEThTemp;
    if(lpSockAddr){
    SOCKADDR*addr=*lpSockAddr;
    intaddrlen=lpSockAddr->GetSize();
    hTemp=accept(m_hSocket,addr,&addrlen);
    }else{
    hTemp=accept(m_hSocket,NULL,NULL);
    }
    rConnectedSocket.Attach(INVALID_SOCKET);
    if(hTemp==INVALID_SOCKET)
    {
    DWORDdwProblem=GetLastError();
    TRACE(“GetLastError()=%d\n",dwProblem);
    SetLastError(dwProblem);
    }
    rConnectedSocket.Attach(hTemp);
    return(hTemp!=INVALID_SOCKET);
    }
    //连接监听
    BOOLCBlockingSocket::Listen(intnConnectionBacklog)
    {
    if(listen(m_hSocket,nConnectionBacklog)==
    SOCKET_ERROR){
    returnFALSE;
    }else{
    returnTRUE;
    }
    }
    //数据接收
    intCBlockingSocket::Receive(void*
    lpBuf,intnBufLen,intnFlags)
    {
    if(m_ReceiveTimeout==INFINITE){
    returnrecv(m_hSocket,(LPSTR)
    lpBuf,nBufLen,nFlags);
    }else{
    fd_setrfds;
    structtimevaltv;
    intretval;
    FD_ZERO(&rfds);
    FD_SET(m_hSocket,&rfds);
    //
    tv.tv_sec=m_ReceiveTimeout/1000;
    tv.tv_usec=(m_ReceiveTimeout%1000)*1000;
    retval=select(1,&rfds,NULL,NULL,&tv);
    if(retval){
    returnrecv(m_hSocket,(LPSTR)lpBuf,nBufLen,nFlags);
    }else{
    return0;//Timeout
    }
    }
    }
    //一个文字接受
    intCBlockingSocket::Receive()
    {intret=0;
    if(m_BufferPointer>=m_BufferLength){
    m_BufferPointer=0;
    m_BufferLength=Receive((char*)m_
    RecvBuffer,sizeof(m_RecvBuffer));
    if(m_BufferLength==0)return-1;
    }
    returnm_RecvBuffer[m_BufferPointer++];
    }
    //送信
    intCBlockingSocket::Send(constvoid
    *lpBuf,intnBufLen,intnFlags)
    {
    returnsend(m_hSocket,(LPSTR)lpBuf,nBufLen,nFlags);
    }
    //Endiffile.
    服务器程序SV
    //SVDlg.h中定义
     HANDLEm_hThread;
     staticDWORDWINAPIThreadProc(CSVDlg*dlg);
    //SVDlg.CPP加入
    BOOLCSVDlg::OnInitDialog()
    {
    ....
    DWORDthreadID;
    m_hThread=CreateThread(NULL,0,
    (LPTHREAD_START_ROUTINE)
    CSVDlg::ThreadProc,
    (LPVOID)this,0,&threadID);
    returnTRUE;
    //returnTRUEunlessyousetthefocustoacontrol
    }
    DWORDWINAPICSVDlg::ThreadProc(CSVDlg*dlg)
    {
    CBlockingSocketsocket;
    socket.Socket(SOCK_DGRAM,IPPROTO_UDP);
    CSockAddraddr(NULL,10000);
    addr.Dump();
    socket.Bind(addr);
    while(1){
    CSockAddrfrom;
    charbuf[128];
    intlen=socket.ReceiveFrom(buf,sizeof(buf),from);
    if(len>0){
    buf[len]=0;
    CStringstr;
    str.Format(“%s%s%d\n",buf,
    from.GetIPString(),from.GetPort());
    ::MessageBox(dlg->m_hWnd,str,“SV",MB_OK);
    socket.SendTo(buf,len,from);
    }else
    break;
    }
    socket.Close();
    return0;
    }
    客户端程序CL中加入:
    voidCCLDlg::OnSendButton()
    {
    CStringip;
    m_IPEdit.GetWindowText(ip);
    CBlockingSocketsocket;
    socket.Socket(SOCK_DGRAM,IPPROTO_UDP);
    CSockAddraddr(NULL,10001);
    socket.Bind(addr);
    CSockAddrsendaddr(ip,10000);
    socket.SendTo(“test",4,sendaddr);
    charbuf[128];
    intlen=socket.ReceiveFrom(buf,sizeof(buf),addr);
    buf[len]=0;
    CStringstr;
    str.Format(“%s%s%d\n",buf,
    addr.GetIPString(),addr.GetPort());
    MessageBox(str,“CL",MB_OK);
    socket.Close();
    }----程序在VC++6.0下编译通过,在使用TCP/IP协议的Windows95/98对等局域网和使用TCP/IP协议的WindowsNT局域网上运行良好。
    (完)
      

  5.   

    int InitTftpServer(unsigned short port)
    {
    int fd;
    struct sockaddr_in local;
    int ret; local.sin_family = AF_INET;
    local.sin_port = htons(port);
    local.sin_addr.s_addr = htonl(INADDR_ANY); fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0)
    {
    AfxMessageBox("Init TFTP Server Error");
    return -1;
    }
    ret = bind(fd, (struct sockaddr *)&local, sizeof(local));
    if (ret < 0)
    {
    AfxMessageBox("TFTP Server Bind Error");
    return -1;
    }
    return fd;
    }
    //Process something from TFTP CLIENT
    UINT  HandleTftp(LPVOID lpParam)
    {
    struct sockaddr_in from;
    int from_len;
    char buffer[2048];
    int len;
    int ret; int fd; 
    fd =  InitTftpServer(69); if (fd < 0)
    return -1;
    char tmp[123];
    sprintf(tmp, "fd = %d\n", fd);
    AfxMessageBox(tmp); while(1)
    {
    CString tmpstr; memset((void *)buffer, 0, sizeof(buffer));
    len = recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr *)&from, &from_len);
    //if (len == SOCKET_ERROR)
    tmpstr.Format("recvlen = %d", len);
    //AfxMessageBox(tmpstr);
    if (len < 0)
    {
    //AfxMessageBox("Recv Data Error");
    continue;
    }
    ret = ProcessTftpData(fd, buffer, (struct sockaddr *)&from);
    }
    return 0;
    }
    void CFactoryProgramDlg::OnStart() 
    {
    // TODO: Add your control notification handler code here
    AfxBeginThread(HandleTftp,(LPVOID)NULL,THREAD_PRIORITY_NORMAL,
      0,0,NULL);
    );}
    很简单的一个测试程序, 启动后用netstat -na 都可以看到在69端口上听,但用扫描程序却发现69端口没有打开,  但就是接收不到数据
      

  6.   

    len = recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr *)&from, &from_len);
    其中的 from_len 未初始化。
    from_len = sizeof(from);