我用C编写了一个简单的TCP服务器客户端本机应用程序。它按预期工作(Linux Fedora和Windows 10的Cygwin(。当我使用EM++(或EMCC(编译它时,它构建了JS&WASM很好。
$em++TcpService.cpp-o TcpService.js ASYNCIFY=1
但是,在运行服务器时,我看到以下错误;尽管它一直在等待客户端数据的到来,但它从未真正连接:
$node TcpService.js
正在等待消息的到达。。。
类型错误:无法读取未定义的属性"流">
类型错误:无法读取未定义的属性"流">
我把问题缩小到接受电话。注意,之前,除了上面的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 socketn");
}
// 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 socketn");
}
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 listeningn");
}
// 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 datan");
}
int n = 0;
int len = 0, maxlen = 100;
char buffer[maxlen];
char *pbuffer = buffer;
printf("client connected with ip address: %sn",
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 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 socketn");
}
if (connect(_Sock, (struct sockaddr*)&server_address,
sizeof(server_address)) < 0) {
printf("could not connect to servern");
return;
}
const char* data_to_send = "test message";
send(_Sock, data_to_send, strlen(data_to_send), 0);
}
在谷歌上搜索错误"TypeError:无法读取未定义的属性'stream'"并不是很有用,尤其是WRT流属性-大多数页面只与AWS相关,而我的页面是一个简单的本地测试程序。
在让node运行应用程序之前,我还安装了所需的websockets NPM。
如果现有的TCP网络代码是用C/C++编写的,并使用Posix Sockets API,默认情况下,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套接字函数以这种方式代理:socket((、socketpair((、shutdown((、bind。以下POSIX套接字函数当前未被代理(将不起作用(:poll((、close(((改用shutdown(((、select((要使用POSIX套接字代理,请使用标志"-lwebsocket.js-s PROXY_POSIX_sockets=1-s use_PTHREADS=1-s PROXY_To_PTHREAD=1"链接应用程序。也就是说,POSIX套接字代理构建在Emscripten WebSockets库之上,需要多线程处理并将应用程序main((代理到pthread。
有关POSIXSockets代理服务器如何在Emscripten客户端程序中工作的示例,请参阅文件tests/websocket/tcp_echo_client.cpp。
https://emscripten.org/docs/porting/networking.html