添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm having issues implementing a C UDP socket program. The code below works perfectly with any input shorter than 56 characters, but if I feed it 56 characters or more, sendto complains that I gave it invalid arguments (error code 22). For instance, this will send correctly:

 ./talkerDemo localhost qqqqqwwwwweeeeeqqqqqwwwwweeeeeqqqqqwwwwweeeeeqqqqqwwwww

But this won't:

 ./talkerDemo localhost qqqqqwwwwweeeeeqqqqqwwwwweeeeeqqqqqwwwwweeeeeqqqqqwwwwwH

What gives?

** talker.c ** Adapted from http://beej.us/guide/bgnet/html/single/bgnet.html#datagram #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define SERVERPORT "4242" // the port users will be connecting to int main(int argc, char *argv[]) int sockfd; struct addrinfo hints, *servinfo, *p; int rv; int numbytes; if (argc != 3) { fprintf(stderr,"usage: talker hostname message\n"); exit(1); memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; // loop through all the results and make a socket for(p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { perror("talker: socket"); continue; break; if (p == NULL) { fprintf(stderr, "talker: failed to create socket\n"); return 2; //============================================================ // !!!!!!! Eror occurs here: if ((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, p->ai_addr, p->ai_addrlen)) == -1) { perror("talker: sendto"); exit(1); //============================================================ freeaddrinfo(servinfo); printf("talker: sent %d bytes to %s\n", numbytes, argv[1]); close(sockfd); return 0;

This was the version of the code I was actually running. Before posting the question, I had gone back to the original (above) to see if the problem occurred with that implementation too - and I seemed it was. But it turns out I was being thick and was using the wrong binary... derp

** UDPTalker.hpp -- a datagram sockets "server" ** Adapted from http://beej.us/guide/bgnet/html/single/bgnet.html#datagram #ifndef UDPTALKER_H #define UDPTALKER_H #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <iostream> #include <string> #define UDPT_DEFAULT_PORT "4243" #define UDPT_DEFAULT_HOST "localhost" #define UDPT_MAXBUFLEN 2048 class UDPTalker { int sockfd; struct addrinfo hints, *servinfo, *p; int rv; int numbytes; std::string host; std::string port; public: //! Takes target hostname/ip and port as arguments. Defaults: ("localhost", "4243") UDPTalker(std::string host = UDPT_DEFAULT_HOST, std::string port = UDPT_DEFAULT_PORT); ~UDPTalker(); void send(std::string msg); #endif // UDPTALKER_H

Here's the corresponding .cpp:

// File UDPTalker.cpp
#include "UDPTalker.hpp"
UDPTalker::UDPTalker(std::string h, std::string port) : host(h), port(port) {
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    if ((rv = getaddrinfo(host.c_str(), port.c_str(), &hints, &servinfo)) != 0) {
        throw std::runtime_error(std::string("getaddrinfo: ").append(gai_strerror(rv)));
    // loop through all the results and make a socket
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("talker: socket");
            continue;
        break;
    freeaddrinfo(servinfo);
    if (p == NULL) {
        throw std::runtime_error("talker: failed to create socket\n");
UDPTalker::~UDPTalker() {
    close(sockfd);
void UDPTalker::send(std::string msg) {
    if ((numbytes = sendto(sockfd, msg.c_str(), msg.size(), 0,
             p->ai_addr, p->ai_addrlen)) == -1) {
        perror("talker: sendto! ");
    // printf("talker: sent %d bytes to %s\n", numbytes, host.c_str());
                Error code 22 is EINVAL. Per the sendto() documentation, EINVAL only occurs when: "The dest_len argument is not a valid length for the address family", which is not the case here (since getaddrinfo() should always provide a valid address length).  So, short of a buffer overflow that corrupts the ai_addrlen, there is no other way that the length of argv[2] would cause an EINVAL error, especially at such low lengths that you are working with (if you were sending more data than could fit in a single UDP datagram, you would get an EMSGSIZE error code instead).
– Remy Lebeau
                Jul 12, 2018 at 0:35
                suggest reading the MAN page for sendto(), especially this sentence: If  the  message  is too long to pass atomically through the underlying        protocol, the error EMSGSIZE is returned, and the message is not transmitted.
– user3629249
                Jul 12, 2018 at 2:37
                have you done any debugging, like displaying the values in: p->ai_family p->ai_socktype, and                 p->ai_protocol to see what, exactly, what type of socket is being generated?
– user3629249
                Jul 12, 2018 at 2:44
                I seem to be able to compile and run the code without any issues with both input! uname -a Linux 94590e76f22f 4.13.0-1011-gcp #15-Ubuntu SMP Mon Feb 12 16:29:04 UTC 2018 x86_64 GNU/Linux
– fnisi
                Jul 12, 2018 at 2:51
                Thanks for all your help! I eventually found my silly mistake. The code I was actually using was adapted from the one I sent above. It was integrated into a C++ class and it seems freeaddrinfo was happening before sendto, invalidating p. But before posting the question, I reverted to the original version of the code (the one I posted), and was getting the same error. Turns out my brain wasn't on and I was using the wrong binary. derp
– Sean Bone
                Jul 12, 2018 at 9:49

freeaddrinfo(servinfo); frees up the memory used by servinfo. This means that the pointer p is now pointing to empty memory, so when it gets passed to sendto it may have invalid content. My guess is that for some reason the extra byte in the input string was "rolling over" that memory location when the class' send method was being called. The fix was moving freeaddrinfo(servinfo); from the constructor to the destructor:

UDPTalker::UDPTalker(std::string h, std::string port) : host(h), port(port) {
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    if ((rv = getaddrinfo(host.c_str(), port.c_str(), &hints, &servinfo)) != 0) {
        throw std::runtime_error(std::string("getaddrinfo: ").append(gai_strerror(rv)));
    // loop through all the results and make a socket
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("talker: socket");
            continue;
        break;
    if (p == NULL) {
        throw std::runtime_error("talker: failed to create socket\n");
UDPTalker::~UDPTalker() {
    freeaddrinfo(servinfo);
    close(sockfd);
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.