使用 c++ 服务器制作 Websocket

Posted

技术标签:

【中文标题】使用 c++ 服务器制作 Websocket【英文标题】:making the Websocket using the c++ server 【发布时间】:2012-03-25 12:17:41 【问题描述】:

我正在用 C++ 制作服务器以连接到 WebSocket,但不知何故,它没有与 WebSocket 连接。 WebSocket 显示连接已关闭,并且 c++ 服务器中也存在一些问题,如从 WebSocket 对服务器的第二次调用,它显示以下错误 - 双重释放或损坏(输出)。我花了很多时间。这是代码: c++

#include<iostream>
#include <string>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>


using namespace std;

string getConnectionKey(char*);
void acceptConnection(int, const char*);
void readConnection(int);
void bail(char*);
string executeShellCommand(const string&);
string getBase64Encoded(string);
char *getClientKey(char*);
string getSHA1Hash(string);

int main()

  char srvr_adr[]  = "127.0.0.1";
  char srvr_port[] = "9099";

  struct sockaddr_in adr_srvr;
  struct sockaddr_in adr_clnt;

  socklen_t len_inet;
  int s;       // Server Socket
  int c;      // Client Socket
  int z;
  char *data;
  char readdata[256];

  int count = 2;

  data  = (char*)malloc(sizeof(char)*128);

  s = socket(PF_INET, SOCK_STREAM, 0);

  if(s  ==  -1)
    bail("socket()");

  memset(&adr_srvr,0,sizeof(adr_srvr));
  adr_srvr.sin_family = AF_INET;
  adr_srvr.sin_port = htons(atoi(srvr_port));

  if( strcmp(srvr_adr,"*")!=0)
  
    adr_srvr.sin_addr.s_addr  = inet_addr(srvr_adr);
    if(adr_srvr.sin_addr.s_addr ==  INADDR_NONE)
      bail(" INVALID ADRESS \n");
  
  else /* WILD ADDRESS*/
    adr_srvr.sin_addr.s_addr  = INADDR_ANY;

  len_inet  = sizeof adr_srvr;
  z = bind(s,(struct sockaddr*)&adr_srvr, len_inet);

  if(z==-1)
    bail("bind(2)");

  z = listen(s,10);

  if(z==-1)
    bail("listen(2)");

  for(;;)
  
    len_inet  = sizeof(adr_clnt);
    c = accept(s, (struct sockaddr*)&adr_clnt,&len_inet);

    if(c==-1)
      bail("accept(2)");

    readConnection(c);

    close(c);
  
  return 0; 


void readConnection(int c)

    int z;
    char readdata[256];

    // READING
    z = read(c,readdata, sizeof(readdata)-1);
    if(z==-1)
      bail("read(2)");
    else if(strlen(readdata)>0)
      printf(" READ \n%s\n", readdata);

    string key =  getConnectionKey(readdata);
    cout<<" KEY "<<key<<endl;
    acceptConnection(c, key.c_str());


void acceptConnection(int c, const char *key)

    int z;      
    char response[]  = "HTTP/1.1 101 Switching Protocols\nUpgrade: websocket\nConnection: Upgrade\nSec-WebSocket-Accept: ";
    char *output;
    output  = (char*)malloc( sizeof(char) * ( strlen(key) + strlen(response) + 1) );
    strcat(output, response);
    strcat(output, key);

    cout<<" output "<<output<<endl;
    // WRITING
    z = write(c, output, strlen(output));
    if(z  ==  -1)
      bail("write(2)");

    printf(" Connection Done \n"); 


string getConnectionKey(char *str)

  char *start,*end,*key;
  int len;
  string s("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");

  // GET CLIENT KEY
  key = getClientKey(str);

  // Appending the key
  s = key + s;

  // SHA1 HASH
  string out  = getSHA1Hash(s);
  //hashwrapper *h  = new sha1wrapper();
  //string out  = h->getHashFromString(s);

  // BASE 64 ENCODING
  string encoded = getBase64Encoded(out);
  //encoded = (char*)malloc(sizeof(char)*256);
  //strcpy(encoded, getBase64Encoded(out) );

  free(key);
  //delete h;
  return encoded;

char *getClientKey(char *str)

  int len;
  char *start,*end,*key;

  start  = strstr(str,  "Sec-WebSocket-Key:");
  if(start ==  NULL)
    return false;
  start +=  17;

  end = strstr(start, "==");
  if(end  ==  NULL)
    return false;

  end++;

  while( !(*start>=65 && *start<=90 || *start >= 97 &&  *start<=122 || *start>=48 && *start<=57 || *start == '+' || *start=='/') )
    start++;
  len = end - start + 1;
  key = (char*) malloc( sizeof(char) * (len+1) );
  strncpy(key,start,len);

  return key;


string getBase64Encoded(string s)

  int len;
  string str="";
  len = s.length();
  char *command;

  for(int i=len-1 ; i>=1; i=i-2)
  
    str = s.substr(i-1,2) + str;
    str = "\\x" + str;
  
  if(len%2==1)
  
    str = s[0]  + str;
    str = "\\x" + str;
  
  // making the command to be send to shell
  str = "printf \"" + str ;
  str = str + "\" | base64";

  cout<<endl<<" STRING "<<str<<endl;
  return executeShellCommand(str);

string getSHA1Hash(string str)

  int len ;
  string output;
  str = "printf \""+str;
  str = str +"\" | sha1sum";
  cout<<str<<endl;
  output  = executeShellCommand(str);

  return output.substr(0,output.length()-4);;

string executeShellCommand(const string& cmd)

   FILE *fpipe;

   if ( !(fpipe = (FILE*)popen(cmd.c_str(),"r")) )
     // If fpipe is NULL
     perror("Problems with pipe");
     exit(1);
   

   char buf[256] = "";
   string line="";
   while ( fgets( buf, sizeof buf, fpipe)  )
   
     if(strlen(buf)>0)
        line.append(buf);
     memset(buf, 0, sizeof(buf));

   
   // CLOSE THE PIPE
    pclose(fpipe);

   return line;

void bail(char *on_what)

  if(errno!=0)
  
    fputs( strerror(errno), stderr);
    fputs( ":", stderr);
  
  fputs( on_what, stderr);
  fputs("\n",stderr);

这是 Websocket 代码:

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<section id="content"></section>
<input id="message" type="text" tabindex="1"/>
<textarea id="show">
</textarea>
<script src="http://www.google.com/jsapi"></script>
<script>google.load("jquery", "1.3")</script>
<script src="http://jquery-json.googlecode.com/files/jquery.json-2.2.min.js"></script>
<!--script src="http://jquery-websocket.googlecode.com/files/jquery.websocket-0.0.1.js"></script-->
<script src="/js/jquery.websocket-0.0.1.js"></script>
<script type="text/javascript">

/*var ws =  $.websocket("ws://127.0.0.1:9099/", 
          
            events: 
                            message: function(e) 
                            
                              alert("e.data");
                              $('#content').append(e.data + '<br>') 
                            
                    
          );*/
var websocketConnection = new WebSocket("ws://127.0.0.1:9099/");
websocketConnection.onopen = function(ev)

        showmsg('Connected to the echo service');
;
websocketConnection.onerror = function(ev)

  showmsg(" ERROR : ".ev.data);

websocketConnection.onclose = function(ev)

  showmsg(" Connection Closed");
;
websocketConnection.onmessage = function(event) 

      showmsg(event.data);
      $('#content').append(event.data+"<br>");
;
showmsg(" CURRENT STATE "+websocketConnection.readyState);
if(!websocketConnection)
  showmsg(" object null ");
websocketConnection.send("Hello Echo Server");

$('#message').change(function()
      flag  = ws.send('message', this.value);
      if(!flag)
        alert("not send");

        this.value = '';
        );
function showmsg(content)

  $('#show').val(content+"<br>");

</script>
</body>
</html>

请帮帮我,C++ 中的问题是什么以及要发送到 WebScoket 的响应是什么。

【问题讨论】:

【参考方案1】:

这是一个问题(在executeShellCommand() 函数中):

command = (char*) malloc( sizeof(char)  * cmd.length()  );
line  = (char*)malloc(sizeof(char)*256);
line[0] = '\0';
//cout<<" COMMAND "<<cmd<<endl;
strcpy(command, cmd.c_str() ); // Writes one beyond the end of the
                               // 'command' buffer as no space allocated
                               // for null terminator

您可以将cmd.c_str() 直接传递给popen(),而不是为此目的分配和填充command 缓冲区:

if ( !(fpipe = (FILE*)popen(cmd.c_str(),"r")) )

我建议在可能的情况下将char* 替换为std::string,并允许它为您管理内存并在std::string 不合适时使用堆栈分配的缓冲区而不是动态分配缓冲区。例如:

std::string executeShellCommand(const std::string& cmd)

  FILE *fpipe;

  if ( !(fpipe = (FILE*)popen(cmd.c_str(),"r")) )
    // If fpipe is NULL
    perror("Problems with pipe");
    exit(1);
  

  char buf[256] = "";
  std::string line;
  while ( fgets( buf, sizeof buf, fpipe)  )
  
    line += buf;
    memset(buf, 0, sizeof(buf));
  
  // CLOSE THE PIPE
  pclose(fpipe);

  return line;

【讨论】:

仍然无法正常工作。在网络套接字的第二次,它在 line+=buf 处给出内存损坏错误。为什么我发送的密钥正确时正在建立 websocket 连接。

以上是关于使用 c++ 服务器制作 Websocket的主要内容,如果未能解决你的问题,请参考以下文章

使用 ClientWebSocket .net 核心测试 TestHost.WebSocketClient

用Wix手工编辑XML制作C++ MSI安装程序,怎样保证安装新版本时候强制卸载旧版本,急急急!!!

如何使用 OpenCV 从 C++ 程序制作 Android 应用程序

Nana 用 C++ 制作 GUI

如何使用 xcode 制作简单的 OpenGl C++ 程序

使用 Fast/Faster-RCNN 在 C++ 上制作对象检测器的最简单方法是啥?