Javascript Webassembly(C+;+;)中的TCP服务器因接受()而失败

Javascript Webassembly(C+;+;)中的TCP服务器因接受()而失败,javascript,c++,sockets,tcp,webassembly,Javascript,C++,Sockets,Tcp,Webassembly,我用C编写了一个简单的TCP服务器客户端本机应用程序。它可以正常工作(LinuxFedora和CygwinforWindows10)。当我使用EM++(或EMCC)编译它时,它构建了JS&wasmfine $em++TcpService.cpp-o TcpService.js-s ASYNCIFY=1 但是,在运行服务器时,我看到以下错误:;虽然它一直在等待客户端数据的到来,但它从未真正连接: $node TcpService.js 正在等待消息到达 TypeError:无法读取未定义的属性“s

我用C编写了一个简单的TCP服务器客户端本机应用程序。它可以正常工作(LinuxFedora和CygwinforWindows10)。当我使用EM++(或EMCC)编译它时,它构建了JS&wasmfine

$em++TcpService.cpp-o TcpService.js-s ASYNCIFY=1

但是,在运行服务器时,我看到以下错误:;虽然它一直在等待客户端数据的到来,但它从未真正连接:

$node TcpService.js

正在等待消息到达

TypeError:无法读取未定义的属性“stream”

TypeError:无法读取未定义的属性“stream”

我把问题缩小到接受电话。注意,在前面,除了上面的TypeError之外,我还会看到stacktrace(不是很有用)。现在我正在使用“-s ASYNCIFY=1”编译代码,堆栈跟踪消失了。但是,客户端程序仍然无法连接(既不是本机构建,也不是其WASM)

服务器程序使用简单的BSD套接字:

void server(void)
{
  // port to start the server on
  int SERVER_PORT = 8877;

  // socket address used for the server
  struct sockaddr_in _ServerAddr;
  memset(&_ServerAddr, 0, sizeof(_ServerAddr));
  _ServerAddr.sin_family = AF_INET;

  // htons: host to network short: transforms a value in host byte
  // ordering format to a short value in network byte ordering format
  _ServerAddr.sin_port = htons(SERVER_PORT);

  // htonl: host to network long: same as htons but to long
  _ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);

  // create a TCP socket, creation returns -1 on failure
  int listen_sock;
  if ((listen_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
    throw std::runtime_error("could not create listen socket\n");
  }

  // bind it to listen to the incoming connections on the created server
  // address, will return -1 on error
  if ((bind(listen_sock, (struct sockaddr *)&_ServerAddr,
            sizeof(_ServerAddr))) < 0) {
    throw std::runtime_error("could not bind socket\n");
  }

  int wait_size = 16;  // maximum number of waiting clients, after which
                       // dropping begins
  if (listen(listen_sock, wait_size) < 0) {
    throw std::runtime_error("could not open socket for listening\n");
  }

  // socket address used to store client address
  struct sockaddr_in client_address;
  int client_address_len = 0;

  // run indefinitely
  while (true) {

    // open a new socket to transmit data per connection
    int sock;
    printf("Waiting for arrival of messages ...\n");
    if ((sock =
             accept(listen_sock, (struct sockaddr *)&client_address,
                    (socklen_t *)&client_address_len)) < 0) {
      throw std::runtime_error("could not open a socket to accept data\n");
    }
    int n = 0;
    int len = 0, maxlen = 100;
    char buffer[maxlen];
    char *pbuffer = buffer;

    printf("client connected with ip address: %s\n",
           inet_ntoa(client_address.sin_addr));

    // keep running as long as the client keeps the connection open
    while ((n = recv(sock, pbuffer, maxlen, 0)) > 0) {
      pbuffer += n;
      maxlen -= n;
      len += n;

      printf("received: '%s'\n", buffer);

      // echo received content back
      send(sock, buffer, len, 0);
    }

    close(sock);
  }

  close(listen_sock);
}
void服务器(void)
{
//用于启动服务器的端口
int SERVER_PORT=8877;
//用于服务器的套接字地址
服务器地址中的结构sockaddr\u;
memset(&_ServerAddr,0,sizeof(_ServerAddr));
_ServerAddr.sin_family=AF_INET;
//htons:host-to-network short:转换主机字节中的值
//排序格式为网络字节排序格式中的短值
_ServerAddr.sin\u port=htons(服务器\u端口);
//htonl:主机到网络的长度:与htons相同,但为长
_ServerAddr.sin\u addr.s\u addr=htonl(INADDR\u ANY);
//创建TCP套接字,创建失败时返回-1
int listen_sock;
如果((侦听\u sock=socket(PF\u INET,sock\u STREAM,0))<0){
抛出std::runtime_错误(“无法创建侦听套接字\n”);
}
//绑定它以侦听所创建服务器上的传入连接
//地址,出错时将返回-1
if((bind(listen_sock,(struct sockaddr*)和_ServerAddr),
sizeof(_ServerAddr)))<0){
抛出std::runtime_错误(“无法绑定套接字\n”);
}
int wait_size=16;//等待的客户端的最大数量,之后
//开始下降
如果(侦听(侦听袜子,等待大小)<0){
抛出std::runtime_错误(“无法打开套接字进行侦听\n”);
}
//用于存储客户端地址的套接字地址
客户端地址中的结构sockaddr\u;
int client_address_len=0;
//无限期运行
while(true){
//打开一个新的套接字以传输每个连接的数据
int袜子;
printf(“等待消息到达…\n”);
如果((袜子=
接受(侦听sock,(结构sockaddr*)和客户端地址,
(socklen_t*)和客户地址(地址)<0){
抛出std::runtime_错误(“无法打开套接字以接受数据\n”);
}
int n=0;
int len=0,maxlen=100;
字符缓冲区[maxlen];
char*pbuffer=缓冲区;
printf(“与ip地址连接的客户端:%s\n”,
inet_ntoa(客户地址sin地址);
//只要客户端保持连接打开,就保持运行
而((n=recv(sock,pbuffer,maxlen,0))>0){
pbuffer+=n;
maxlen-=n;
len+=n;
printf(“收到:'%s'\n',缓冲区);
//回显接收到的内容
发送(sock,buffer,len,0);
}
关闭(袜子);
}
关闭(听短袜);
}
客户机同样简单:

void sendMessage(void)
{
  memset(&server_address, 0, sizeof(server_address));
  server_address.sin_family = AF_INET;

  inet_pton(AF_INET, server_name, &server_address.sin_addr);

  server_address.sin_port = htons(server_port);
  if ((_Sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
    printf("could not create socket\n");
  }

  if (connect(_Sock, (struct sockaddr*)&server_address,
             sizeof(server_address)) < 0) {
    printf("could not connect to server\n");
    return;
  }
  const char* data_to_send = "test message";
  send(_Sock, data_to_send, strlen(data_to_send), 0);
}
void发送消息(void)
{
memset(&server_地址,0,sizeof(server_地址));
服务器地址.sin\u family=AF\u INET;
inet\u pton(AF\u inet、服务器名称和服务器地址。sin\u addr);
server\u address.sin\u port=htons(server\u port);
如果(_Sock=socket(PF_INET,Sock\u STREAM,0))<0){
printf(“无法创建套接字\n”);
}
如果(连接(_Sock,(struct sockaddr*)和服务器地址,
sizeof(服务器地址))<0){
printf(“无法连接到服务器\n”);
返回;
}
const char*data_to_send=“测试消息”;
send(_Sock,data-to-send,strlen(data-to-send),0);
}
谷歌搜索错误“TypeError:无法读取未定义的属性'stream'”证明不是很有用,尤其是WRT stream属性-大多数页面仅与AWS相关,而我的是一个简单的本地测试程序


在让node运行应用程序之前,我还安装了所需的websockets NPM。

如果您有使用Posix Sockets API的C/C++编写的现有TCP网络代码,默认情况下,Emscripten会尝试通过WebSocket协议模拟此类连接。要使其正常工作,您需要在服务器端使用WebSockify之类的工具,以使TCP服务器堆栈能够接收传入的WebSocket连接。此仿真目前还不是很完整,您可能会遇到开箱即用的问题,需要调整代码以在该仿真提供的限制范围内工作

这是POSIX套接字的默认构建模式,无需链接器标志或选项设置即可启用

WebSocket代理服务器上的完整POSIX套接字 Emscripten提供了一个本地POSIX套接字代理服务器程序,位于tools/websocket_to_POSIX_proxy/目录中,该程序允许从web浏览器完全访问POSIX套接字API。此支持通过将所有POSIX套接字API调用从浏览器代理到Emscripten POSIX套接字代理服务器(通过透明使用WebSockets API),然后代理服务器代表页面执行本机TCP/UDP调用。这允许web浏览器页面运行完整的TCP和UDP连接,充当服务器以接受传入连接,并执行主机名查找和反向查找。因为所有API调用都是单独代理的,所以这种支持可能会很慢。这种支持对于开发测试基础设施和调试非常有用

以下POSIX套接字函数以这种方式代理: 套接字(),套接字对(),关机(),绑定(),连接(