时间比较匆忙, 写了一个简单的 websocket服务器,采用c++. 网络底层采用windows api.
#include "sockio.h"
#include <iostream>
#include <WS2tcpip.h>
using std::cerr;
using std::cout;
using std::endl;
#define SERVER_PORT 80
#define MSG_BUF_SIZE 1024
WebSocket Server::m_webSocket;
Server::Server()
{
cout << "Initializing server...\n";
//
winsock_ver = MAKEWORD(2, 2);
addr_len = sizeof(SOCKADDR_IN);
addr_svr.sin_family = AF_INET;
addr_svr.sin_port = ::htons(SERVER_PORT);
addr_svr.sin_addr.S_un.S_addr = ADDR_ANY;
memset(buf_ip, 0, IP_BUF_SIZE);
//
ret_val = ::WSAStartup(winsock_ver, &wsa_data);
if (ret_val != 0)
{
cerr << "WSA failed to start up!Error code: " << ::WSAGetLastError() << "\n";
system("pause");
exit(1);
}
cout << "WSA started up successfully...\n";
//
sock_svr = ::socket(AF_INET, SOCK_STREAM, 0);
if (sock_svr == INVALID_SOCKET)
{
cerr << "Failed to create server socket!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit(1);
}
cout << "Server socket created successfully...\n";
//
ret_val = ::bind(sock_svr, (SOCKADDR*)&addr_svr, addr_len);
if (ret_val != 0)
{
cerr << "Failed to bind server socket!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit(1);
}
cout << "Server socket bound successfully...\n";
//
ret_val = ::listen(sock_svr, SOMAXCONN);
if (ret_val == SOCKET_ERROR)
{
cerr << "Server socket failed to listen!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit(1);
}
cout << "Server socket started to listen...\n";
//
cout << "Server started successfully..." << endl;
}
Server::~Server()
{
::closesocket(sock_svr);
::closesocket(sock_clt);
::WSACleanup();
cout << "Socket closed..." << endl;
}
DWORD WINAPI CreateClientThread(LPVOID lpParameter);
//
void Server::WaitForClient()
{
while (true)
{
sock_clt = ::accept(sock_svr, (SOCKADDR*)&addr_clt, &addr_len);
if (sock_clt == INVALID_SOCKET)
{
cerr << "Failed to accept client!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit(1);
}
::InetNtop(addr_clt.sin_family, &addr_clt, buf_ip, IP_BUF_SIZE);
cout << "A new client connected...IP address: " << buf_ip << ", port number: " << ::ntohs(addr_clt.sin_port) << endl;
h_thread = ::CreateThread(nullptr, 0, CreateClientThread, (LPVOID)sock_clt, 0, nullptr);
if (h_thread == NULL)
{
cerr << "Failed to create a new thread!Error code: " << ::WSAGetLastError() << "\n";
::WSACleanup();
system("pause");
exit(1);
}
::CloseHandle(h_thread);
}
}
void parseFrame(WebSocketFrameType frametype)
{/*
ERROR_FRAME=0xFF00,
INCOMPLETE_FRAME=0xFE00,
OPENING_FRAME=0x3300,
CLOSING_FRAME=0x3400,
INCOMPLETE_TEXT_FRAME=0x01,
INCOMPLETE_BINARY_FRAME=0x02,
TEXT_FRAME=0x81,
BINARY_FRAME=0x82,
PING_FRAME=0x19,
PONG_FRAME=0x1A
*/
switch(frametype)
{
case ERROR_FRAME:
break;
case INCOMPLETE_FRAME:
break;
case OPENING_FRAME:
break;
case CLOSING_FRAME:
break;
case INCOMPLETE_TEXT_FRAME:
break;
case INCOMPLETE_BINARY_FRAME:
break;
case TEXT_FRAME:
break;
case BINARY_FRAME:
break;
case PING_FRAME:
break;
case PONG_FRAME:
break;
}
}
DWORD WINAPI CreateClientThread(LPVOID lpParameter)
{
SOCKET sock_clt = (SOCKET)lpParameter;
char buf_msg[MSG_BUF_SIZE];
char sendbuf_msg[MSG_BUF_SIZE];
int ret_val = 0;
int snd_result = 0;
int count=0;
do
{
memset(buf_msg, 0, MSG_BUF_SIZE);
memset(sendbuf_msg, 0, MSG_BUF_SIZE);
ret_val = ::recv(sock_clt, buf_msg, MSG_BUF_SIZE, 0);
if (ret_val > 0)
{
if (strcmp(buf_msg, "exit") == 0)
{
cout << "Client requests to close the connection..." << endl;
break;
}
cout << "Message received: " << buf_msg << endl;
WebSocketFrameType frametype = Server::m_webSocket.parseHandshake((unsigned char*)buf_msg, ret_val);
if(frametype == 1)
{
}
parseFrame(frametype);
count++;
int len =0;
string str;
if(frametype == OPENING_FRAME)
{
str = Server::m_webSocket.answerHandshake();
memcpy(sendbuf_msg, str.c_str(), str.length());
len = str.length();
}
else if(frametype == INCOMPLETE_FRAME)
{
//sprintf(buf_msg, "666666");
//ret_val = 6;
Server::m_webSocket.getFrame((unsigned char*)buf_msg, ret_val, (unsigned char*)sendbuf_msg, MSG_BUF_SIZE, &len);
sprintf(buf_msg,"%s[%d]",sendbuf_msg, count);
ret_val = strlen(buf_msg);
len = Server::m_webSocket.makeFrame(TEXT_FRAME, (unsigned char*)buf_msg, ret_val, (unsigned char*)sendbuf_msg, MSG_BUF_SIZE);
}
else
{
}
snd_result = ::send(sock_clt,sendbuf_msg,len,0);
if( snd_result == SOCKET_ERROR)
{
cerr << "Failed to send message to client!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return 1;
}
if(count > 100)
{
ret_val = strlen(buf_msg);
len = Server::m_webSocket.makeFrame(CLOSING_FRAME, (unsigned char*)buf_msg, ret_val, (unsigned char*)sendbuf_msg, MSG_BUF_SIZE);
snd_result = ::send(sock_clt,sendbuf_msg,len,0);
if( snd_result == SOCKET_ERROR)
{
cerr << "Failed to send message to client!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return 1;
}
//::closesocket(sock_clt);
//system("pause");
// return 1;
}
}
else if (ret_val == 0)
{
cout << "connection closed..." << endl;
}
else
{
cerr << "Failed to receive message from client!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return 1;
}
} while (ret_val > 0);
//
ret_val = ::shutdown(sock_clt, SD_SEND);
if (ret_val == SOCKET_ERROR)
{
cerr << "Failed to shutdown the client socket!Error code: " << ::GetLastError() << "\n";
::closesocket(sock_clt);
system("pause");
return 1;
}
return 0;
}
//----------------------------------------------------------------------------------------------------------------------------------------------
//----------------------------websocket.h------------------------------------
#ifndef WEBSOCKET_H
#define WEBSOCKET_H
#include <assert.h>
#include <stdint.h> /* uint8_t */
#include <stdio.h> /* sscanf */
#include <ctype.h> /* isdigit */
#include <stddef.h> /* int */
// std c++
#include <vector>
#include <string>
using namespace std;
enum WebSocketFrameType {
ERROR_FRAME=0xFF00,
INCOMPLETE_FRAME=0xFE00,
OPENING_FRAME=0x3300,
CLOSING_FRAME=0x3400,
INCOMPLETE_TEXT_FRAME=0x01,
INCOMPLETE_BINARY_FRAME=0x02,
TEXT_FRAME=0x81,
BINARY_FRAME=0x82,
PING_FRAME=0x19,
PONG_FRAME=0x1A
};
class WebSocket
{
public:
string resource;
string host;
string origin;
string protocol;
string key;
WebSocket();
/**
* @param input_frame .in. pointer to input frame
* @param input_len .in. length of input frame
* @return [WS_INCOMPLETE_FRAME, WS_ERROR_FRAME, WS_OPENING_FRAME]
*/
WebSocketFrameType parseHandshake(unsigned char* input_frame, int input_len);
string answerHandshake();
int makeFrame(WebSocketFrameType frame_type, unsigned char* msg, int msg_len, unsigned char* buffer, int buffer_len);
WebSocketFrameType getFrame(unsigned char* in_buffer, int in_length, unsigned char* out_buffer, int out_size, int* out_length);
string trim(string str);
vector<string> explode(string theString, string theDelimiter, bool theIncludeEmptyStrings = false );
};
#endif /* WEBSOCKET_H */
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------测试脚本-----------
<!DOCTYPE html>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script language="javascript"type="text/javascript">
var wsUri ="ws://127.0.0.1:5000/";
var output;
function init() {
output = document.getElementById("output");
testWebSocket();
}
function testWebSocket() {
websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) {
onOpen(evt)
};
websocket.onclose = function(evt) {
onClose(evt)
};
websocket.onmessage = function(evt) {
onMessage(evt)
};
websocket.onerror = function(evt) {
onError(evt)
};
}
function onOpen(evt) {
writeToScreen("CONNECTED");
doSend("WebSocket rocks");
}
function onClose(evt) {
writeToScreen("DISCONNECTED");
}
function onMessage(evt) {
writeToScreen('<span style="color: blue;">RESPONSE: '+ evt.data+'</span>');
websocket.close();
}
function onError(evt) {
writeToScreen('<span style="color: red;">ERROR:</span> '+ evt.data);
}
function doSend(message) {
writeToScreen("SENT: " + message);
websocket.send(message);
}
function writeToScreen(message) {
var pre = document.createElement("p");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
output.appendChild(pre);
}
window.addEventListener("load", init, false);
</script>
<h2>WebSocket Test</h2>
<div id="output"></div>
</html>
//-----------------------------------------------------------------------------------------------------------------------------------------------