HTML5 Websocket 连接到 Windows .NET 服务器,但没有收到 WebSocket.onopen 通知。
Posted
技术标签:
【中文标题】HTML5 Websocket 连接到 Windows .NET 服务器,但没有收到 WebSocket.onopen 通知。【英文标题】:HTML5 Websocket connects to Windows .NET server but does not recieve the WebSocket.onopen notification.. 【发布时间】:2012-05-09 04:27:24 【问题描述】:下面是简单的服务器代码
// Webserver1.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "Webserver1.h"
#ifndef UNICODE
#define UNICODE
#endif
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WEBSERVER1, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
return FALSE;
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WEBSERVER1));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
TranslateMessage(&msg);
DispatchMessage(&msg);
return (int) msg.wParam;
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WEBSERVER1));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WEBSERVER1);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
int ServerThread(LPVOID param)
//----------------------
// Initialize Winsock.
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
wprintf(L"WSAStartup failed with error: %ld\n", iResult);
return 1;
//----------------------
// Create a SOCKET for listening for
// incoming connection requests.
SOCKET ListenSocket;
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET)
wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(27015);
if (bind(ListenSocket,
(SOCKADDR *) & service, sizeof (service)) == SOCKET_ERROR)
wprintf(L"bind failed with error: %ld\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
//----------------------
// Listen for incoming connection requests.
// on the created socket
if (listen(ListenSocket, 1) == SOCKET_ERROR)
wprintf(L"listen failed with error: %ld\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
//----------------------
// Create a SOCKET for accepting incoming requests.
SOCKET AcceptSocket;
wprintf(L"Waiting for client to connect...\n");
//----------------------
// Accept the connection.
AcceptSocket = accept(ListenSocket, NULL, NULL);
if (AcceptSocket == INVALID_SOCKET)
wprintf(L"accept failed with error: %ld\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
else
wprintf(L"Client connected.\n");
char *sendbuf = "Client: sending data test";
char recvbuff[1024];
int dwBytesWrite;
/*
dwBytesWrite = recv(AcceptSocket,recvbuff , (int)sizeof(recvbuff), 0);
if (SOCKET_ERROR == dwBytesWrite )
printf("rev failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return -1;
*/
dwBytesWrite = send(AcceptSocket,sendbuf , (int)strlen(sendbuf), 0);
if (SOCKET_ERROR == dwBytesWrite )
printf("rev failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return -1;
// No longer need server socket
closesocket(ListenSocket);
WSACleanup();
return 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
DWORD dwThreadId;
HANDLE dispthread;
switch (message)
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case ID_FILE_STARTSERVER:
dispthread=CreateThread(NULL,0,LPTHREAD_START_ROUTINE(ServerThread),NULL,0,&dwThreadId);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
return 0;
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
UNREFERENCED_PARAMETER(lParam);
switch (message)
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
break;
return (INT_PTR)FALSE;
这是 html5 客户端代码
<!DOCTYPE html>
<html>
<script type="text/javascript">
function WebSocketTest()
if ("WebSocket" in window)
alert("WebSocket is supported by your Browser!");
// Let us open a web socket
var ws = new WebSocket("ws://127.0.0.1:27015/echo");
ws.onopen = function(evt)
alert("Message i11111");
// Web Socket is connected, send data using send()
ws.send("Message to send");
alert("Message is sent...");
;
ws.onmessage = function (evt)
var received_msg = evt.data;
alert("Message is received...");
;
ws.onerror = function (evt)
// var received_msg = evt.data;
alert("ERROR...!!");
;
ws.onclose = function()
// websocket is closed.
alert("Connection is closed...");
;
else
// The browser doesn't support WebSocket
alert("WebSocket NOT supported by your Browser!");
</script>
<head>
</head>
<body>
<div id="sse">
<a href="javascript:WebSocketTest()">Run WebSocket</a>
</div>
<canvas id="myCanvas" style="border:3px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
</body>
</html>
在调试时我发现客户端连接被服务器接受,但客户端没有收到 onopen 通知,但收到了 onclose 通知,可能是什么问题?
【问题讨论】:
【参考方案1】:客户端的WebSocket只有在双方进行握手并成功时才会抛出onopen事件。 当 WebSocket 连接到服务器时,它会发送包含一些详细信息的 HTTP 开放握手行。它包含重要信息,服务器应根据来自客户端的数据生成 HTTP 开放握手答案。 尤其是来自客户端的密钥,必须进行处理并生成答案密钥。 握手完成并通过验证后,“onopen”事件将在客户端触发,客户端可以在此之后发送消息,服务器也是如此。否则在一些超时之后客户端会抛出 onerror 和 onclose 并且浏览器会强制断开套接字。
查看官方规范RFC 6455, Section 1.3
【讨论】:
我对此很陌生,您能否详细说明或提供一个示例来说明它是如何完成的...... 这是我前段时间的一篇大文章,里面有一些做握手等的代码部分。 ***.com/questions/10200910/… 你也可以在这里找到一些有用的东西:github.com/dude-seriously/gh12-server 在 Protocol 和 Sockets 文件夹下。以上是关于HTML5 Websocket 连接到 Windows .NET 服务器,但没有收到 WebSocket.onopen 通知。的主要内容,如果未能解决你的问题,请参考以下文章
HTML5 Websocket 连接到 Windows .NET 服务器,但没有收到 WebSocket.onopen 通知。
从浏览器请求连接到 C# 程序后,WebSocket 没有响应
WebSocket 不会连接到 127.0.0.1 / localhost 以外的任何东西