Javascript Webassembly(C+;+;)中的TCP服务器因接受()而失败
我用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套接字: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
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套接字函数以这种方式代理: 套接字(),套接字对(),关机(),绑定(),连接(