jjzjj

c++ - 如果我不先创建 TCP 连接,为什么发送数据报不起作用?

coder 2024-06-22 原文

下面的 c++ 程序应该使用套接字数据报将每一行转换为大写,以便在两个线程之间进行通信。

Example:
Hello World!<return>
HELLO WORLD!
123abc!<return>
123ABC!
<return>
<end program>

编写的程序对我有用,但是如果我在主程序中注释 bugfix() 函数调用,程序会在第一行输入后无限期等待。

Example:
Hello World!<return>
<the program wait indefinitely>

这发生在 Windows 7 上,最后一次更新是 10/04/2011 使用最后一个 MinGW32。

#include <iostream>
#include <cstdlib>
#include <cctype>
#include <sys/types.h>
#include <winsock.h>
#include <windows.h>
#include <process.h>

using namespace std;

#define CHECK(exp, cond)  do { typeof(exp) _check_value_ = exp; check(_check_value_ cond, _check_value_, __LINE__, #exp #cond); } while(0)

template <class T>
void check(bool ok, T value, int line, const char* text) {
    if (!ok) {
        cerr << "ERROR(" << line << "):" << text << "\nReturned: " << value << endl;
        cerr << "errno=" << errno << endl;
        cerr << "WSAGetLastError()=" << WSAGetLastError() << endl;
        exit(EXIT_FAILURE);
    }
}

#define DATA_CAPACITY   1000
#define PORT            23584
#define TEST_IP         "192.0.32.10"
#define MYSELF          "127.0.0.1"
#define DST_IP          MYSELF

sockaddr_in address(u_long ip, u_short port) {
    sockaddr_in addr = { };
    addr.sin_family = AF_INET;
    addr.sin_port = port;
    addr.sin_addr.s_addr = ip;
    return addr;
}

void __cdecl client_thread(void* args) {
    SOCKET s = *(SOCKET*)args;

    sockaddr_in addr = address(inet_addr(DST_IP), htons(PORT));

    char data[DATA_CAPACITY];
    while (1) {
        cin.getline(data, DATA_CAPACITY);
        int data_len = strlen(data);

        CHECK(sendto(s, data, data_len, 0, (sockaddr*)&addr, sizeof addr), >= 0);
        CHECK(recvfrom(s, data, DATA_CAPACITY, 0, NULL, NULL), >= 0);

        cout << data << endl;

        if (data_len == 0)
            break;
    }

    CHECK(closesocket(s), == 0);
}

void __cdecl server_thread(void* args) {
    SOCKET s = *(SOCKET*)args;
    sockaddr_in addr = address(INADDR_ANY, htons(PORT));
    int addr_size = sizeof addr;
    CHECK(bind(s, (sockaddr*)&addr, sizeof addr), != SOCKET_ERROR);

    char data[DATA_CAPACITY];
    while (1) {
        int data_len = recvfrom(s, data, DATA_CAPACITY, 0, (sockaddr*)&addr, &addr_size);
        CHECK(data_len, >= 0);

        for (int i = 0; i < data_len; i++)
            if (islower(data[i]))
                data[i] = toupper(data[i]);

        CHECK(sendto(s, data, data_len, 0, (sockaddr*)&addr, addr_size), >= 0);

        if (data_len == 0)
            break;
    }

    CHECK(closesocket(s), == 0);
}

// This function create a TCP connection with www.example.com and the close it
void bugfix() {
    SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    sockaddr_in addr = address(inet_addr(TEST_IP), htons(80));
    connect(s, (sockaddr*)&addr, sizeof addr);
    CHECK(closesocket(s), == 0);
}

int main()
{
    cout << "Convert text to uppercase, an empty line terminate the program" << endl;


    WSADATA wsaData;
    CHECK(WSAStartup(MAKEWORD(2, 2), &wsaData), == 0);

    SOCKET client = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    SOCKET server = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

    CHECK(client, != INVALID_SOCKET);
    CHECK(server, != INVALID_SOCKET);

    // if this function is not called the program doesn't work
    bugfix();

    HANDLE hClient = (HANDLE)_beginthread(client_thread, 0, &client);
    HANDLE hServer = (HANDLE)_beginthread(server_thread, 0, &server);

    HANDLE h[] = { hClient, hServer };

    WaitForMultipleObjects(sizeof h / sizeof *h, h, TRUE, INFINITE);

    CHECK(WSACleanup(), == 0);

    return EXIT_SUCCESS;
}

最佳答案

    int data_len = strlen(data);

Tony Hoare 将他对 NULL 指针的定义称为他的十亿美元错误。以零结尾的字符串一定是丹尼斯·里奇 (Dennis Ritchie) 犯的一百亿美元的错误。加一个。

否则您的程序是发现 UDP 不是可靠协议(protocol)的精心设计的方法。允许网络堆栈任意使 UDP 数据包消失或重新排序。只要在它上面有另一个协议(protocol)可以检测到这一点,就像 TCP 一样,这就可以了。你在没有这种创可贴的情况下飞行,bugfix() 实际上不是解决方法。

使用 TCP,首先发送数据包长度,以便接收方知道后面有多少字节,这样您就不会受到流行为的影响。但更重要的是,通过套接字在线程之间交换数据是一种非常避免使用带互斥锁的数组的昂贵方法。线程可以不受限制地访问进程中的内存,您不需要进程间通信机制来让它们交换数据。

关于c++ - 如果我不先创建 TCP 连接,为什么发送数据报不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5611213/

有关c++ - 如果我不先创建 TCP 连接,为什么发送数据报不起作用?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  5. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  6. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  7. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  8. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  9. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  10. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

随机推荐