繁体   English   中英

UDP在连接的套接字上响应

[英]UDP respond on connected socket

因此,我已经使用TCP编程了一段时间,并决定选择UDP。 我不太确定需要做些什么才能使我在WAN上双向通信(或者通过lan进行通信,因为可以打开两个端口,所以在lan上更容易),一旦我从客户端发送信息到服务器如何在该套接字上响应。 有没有直接连接的方法?

(当前快速功能)

int udpsock(int port, const char* addr){
 int handle = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
 if (handle < 1)
    return -1; 

 sockaddr_in address;
 address.sin_family = AF_INET;
 if (addr == INADDR_ANY)
     address.sin_addr.s_addr = INADDR_ANY;
 else
     address.sin_addr.s_addr = inet_addr(addr);
 address.sin_port = htons( (unsigned short) port );

 if ( bind( handle, (const sockaddr*) &address, sizeof(sockaddr_in) ) < 0 )
     return -1;

 return handle;
}
string recvudp(int sock,const int size){
 sockaddr_in SenderAddr;
 int SenderAddrSize = sizeof (SenderAddr);
 char buf[size];

 int retsize = recvfrom(sock, buf, sizeof(buf), 0, (SOCKADDR *) & SenderAddr, &Sen derAddrSize);
 if (retsize == -1){
     cout << "\nRecv Error : " << WSAGetLastError();
     if (WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == 0){
      return "";
     }
     return "\0";
 }
 else if (retsize < size){
     buf[retsize] = NULL;
 }
 return buf;
}
int sendudp(string str, string ip, unsigned short port, int sock){
 sockaddr_in dest;
 dest.sin_family = AF_INET;
 dest.sin_addr.s_addr = inet_addr( ip.c_str() );
 dest.sin_port = htons( port );

 int ret = sendto(sock,str.c_str(),str.size(),0, (sockaddr*)&dest,sizeof(dest));

 if (ret == -1){
  cout << "\nSend Error Code : " <<  WSAGetLastError();
 }

 return ret;
}

有了这个,很容易制作一个带有端口xxxx的套接字,并让合作伙伴在该端口上发送数据以将数据发送给客户端,第四部分是我遇到麻烦的地方=]

使您的sendudp函数采用sockaddr_in 您可以从recvfrom获得recvfrom ,并将其传递给sendto 或者,传递接收到的sockaddr_in进行connect ,然后使用send

我假设您发布的功能应在客户端和服务器之间共享。 为了实现这一点,需要对其进行略微修改。 例如,在服务器端, recvudp应该返回客户端地址(可能作为out参数),以后再用于将消息发送回该地址。 此外,由于客户端地址结构已经填充(在服务器端的recvudp或在客户端手动地),我们可以将其传递给sendudp作为其参数。

我已经玩了一点,并在Visual Studio 2010中创建了两个简单的项目:UDP服务器和客户端。 它们都使用上述共享功能。 该代码远非完美,仅旨在显示基本的UDP套接字通信。

Shared.h:

#ifndef SHARED_H
#define SHARED_H
#include <winsock2.h>
#include <string>

int udpsock(int port, const char* addr);
std::string recvudp(int sock, const int size, sockaddr_in& SenderAddr, int& SenderAddrSize);
int sendudp(std::string str, sockaddr_in dest, int sock);

#endif

Shared.cpp:

#include "Include\shared.h" // path to header - you might use different one
#include <iostream>
using namespace std;

int udpsock(int port, const char* addr)
{
    int handle = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );

    if (handle < 1)
        return -1; 

    sockaddr_in address;
    address.sin_family = AF_INET;
    if (addr == INADDR_ANY)
        address.sin_addr.s_addr = INADDR_ANY;
    else
        address.sin_addr.s_addr = inet_addr(addr);
    address.sin_port = htons( (unsigned short) port );

    if ( bind( handle, (const sockaddr*) &address, sizeof(sockaddr_in) ) < 0 )
        return -1;

    return handle;
}

// function should return sender address info (for the code the server)
string recvudp(int sock, const int size, sockaddr_in& SenderAddr, int& SenderAddrSize)
{
        // TODO: use std::vector<char> here instead of char array
    char* buf = 0;
    buf = new char[size];

    int retsize = recvfrom(sock, buf, size, 0, (sockaddr*) &SenderAddr, &SenderAddrSize);

    if(retsize == -1)
    {
        cout << "\nRecv Error : " << WSAGetLastError();

        if (WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == 0)
        {
            return "";
        }

        return "\0";
    }
    else if (retsize < size)
    {
        buf[retsize] = NULL;
    }

    string str(buf);
    delete[] buf;

    return str;
}

// On the client side, prepare dest like this:
//  sockaddr_in dest;
//  dest.sin_family = AF_INET;
//  dest.sin_addr.s_addr = inet_addr(ip.c_str());
//  dest.sin_port = htons(port);
int sendudp(string str, sockaddr_in dest, int sock)
{
    int ret = sendto(sock,str.c_str(),str.size(),0, (sockaddr*)&dest,sizeof(dest));

    if (ret == -1)
    {
        cout << "\nSend Error Code : " <<  WSAGetLastError();
    }

    return ret;
}

服务器:main.cpp:

#include <winsock2.h>
#include <string.h>
#include <iostream>
#include "..\Shared\Include\shared.h"

// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

#define SERVER_PORT 27015
#define MAX_MSG 1024

using namespace std;

int main(int argc, char *argv[]) 
{  
    WSADATA wsaData;

    int nResult = WSAStartup(MAKEWORD(2, 2), &wsaData);

    if(nResult != NO_ERROR) 
    {
        cout << "WSAStartup failed with error: " << nResult << endl;
        return 1;
    }

    sock = udpsock(SERVER_PORT, "127.0.0.1");
    cout << "Waiting for datagram on port: " << SERVER_PORT << endl;

    while(1) 
    {
        sockaddr_in clientAddr;     
        // receive message
        int clientAddrLen = sizeof(clientAddr);

        cout << "Received message from the client: " << recvudp(sock, MAX_MSG, clientAddr, clientAddrLen) << endl; 

        sendudp("Hello from server!", clientAddr, sock);
    }

    WSACleanup();
    return 0;
}

客户端:main.cpp:

#include <winsock2.h>
#include <iostream>
#include "..\Shared\Include\shared.h"
using namespace std;

#define MAX_MSG 1024

// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

int main(int argc, char* argv[])
{   
    WSADATA wsaData;

    int nResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (nResult != NO_ERROR) 
    {
        cout << "WSAStartup failed with error: " << nResult << endl;
        return 1;
    }

    SOCKET sock = INVALID_SOCKET;

    // Create a socket for sending data - it does not need to be binded like listening socket!
    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    if(sock == INVALID_SOCKET) 
    {
        cout << socket failed with error: " <<  WSAGetLastError() << endl;
        WSACleanup();
        return 1;
    }

    unsigned short Port = 27015;    

    sockaddr_in dest;
    dest.sin_family = AF_INET;
    dest.sin_addr.s_addr = inet_addr("127.0.0.1");
    dest.sin_port = htons(Port);

    sendudp("Hello from client!", dest, sock);

    sockaddr_in RecvAddr;    
    int recvaddrlen = sizeof(RecvAddr);

    cout << "Received message from the server: " << recvudp(sock, MAX_MSG, RecvAddr, recvaddrlen) << endl; 

    cout << "Closing socket..." << endl; 

    nResult = closesocket(sock);

    if(nResult == SOCKET_ERROR) 
    {
        cout << "closesocket failed with error: " << WSAGetLastError() << endl;
        WSACleanup();
        return 1;
    }

    WSACleanup();
    return 0;
}

如果您运行两次客户端,则输出为:

服务器:

等待端口上的数据报:27015
收到客户端的消息:客户端您好!
收到客户端的消息:客户端您好!

客户:

从服务器收到的消息:您好,服务器!
合闸插座...

UDP是无连接协议,服务器只需要在UDP端口上开始侦听,客户端就可以立即发送数据(数据报),而无需建立连接(例如,在TCP中使用connect() / accept() )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM