Linux下用C编写WebSocet服务以响应HTML5的WebSocket请求

在HTML5中新增了WebSocket,使得通讯变得更加方便。这样一来,Web与硬件的交互除了CGI和XHR的方式外,又有了一个新的方式。那么使用WebSocket又如何与下层通信呢?看看WebSocket的相关介绍就会发现,其类似于HTTP协议的通信,但又不同于HTTP协议通信,其最终使用的是TCP通信。具体的可以参照该文WebScoket 规范 + WebSocket 协议

我们先来看看通信的效果图



下面是实现的步骤

1.建立SOCKET监听

WebSocket也是TCP通信,所以服务端需要先建立监听,下面是实现的代码。

/* server.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include "base64.h"
#include "sha1.h"
#include "intLib.h"


#define REQUEST_LEN_MAX 1024
#define DEFEULT_SERVER_PORT 8000
#define WEB_SOCKET_KEY_LEN_MAX 256
#define RESPONSE_HEADER_LEN_MAX 1024
#define LINE_MAX 256


void shakeHand(int connfd,const char *serverKey);
char * fetchSecKey(const char * buf);
char * computeAcceptKey(const char * buf);
char * analyData(const char * buf,const int bufLen);
char * packData(const char * message,unsigned long * len);
void response(const int connfd,const char * message);

int main(int argc, char *argv[])
{
	struct sockaddr_in servaddr, cliaddr;
	socklen_t cliaddr_len;
	int listenfd, connfd;
	char buf[REQUEST_LEN_MAX];
	char *data;
	char str[INET_ADDRSTRLEN];
	char *secWebSocketKey;
	int i,n;
	int connected=0;//0:not connect.1:connected.
	int port= DEFEULT_SERVER_PORT;

	if(argc>1)
	  {
	    port=atoi(argv[1]);
	  }
	if(port<=0||port>0xFFFF)
	  {
	    printf("Port(%d) is out of range(1-%d)\n",port,0xFFFF);
	    return;
	  }
	listenfd = socket(AF_INET, SOCK_STREAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(port);
    
	bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

	listen(listenfd, 20);

	printf("Listen %d\nAccepting connections ...\n",port);
	cliaddr_len = sizeof(cliaddr);
	connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
	printf("From %s at PORT %d\n",
		       inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
		       ntohs(cliaddr.sin_port));

	while (1)
	  {
	
		memset(buf,0,REQUEST_LEN_MAX);
		n = read(connfd, buf, REQUEST_LEN_MAX);	
		printf("---------------------\n");
	
	
		if(0==connected)
		  {
		    printf("read:%d\n%s\n",n,buf);
		    secWebSocketKey=computeAcceptKey(buf);	
		    shakeHand(connfd,secWebSocketKey);
		    connected=1;
		    continue;
		  }

		data=analyData(buf,n);
		response(connfd,data);
	}
	close(connfd);
}

2.握手

在建立监听后,网页向服务端发现WebSocket请求,这时需要先进行握手。握手时,客户端会在协议中包含一个握手的唯一Key,服务端在拿到这个Key后,需要加入一个GUID,然后进行sha1的加密,再转换成base64,最后再发回到客户端。这样就完成了一次握手。此种握手方式是针对chrome websocket 13的版本,其他版本的可能会有所不同。下面是实现的代码。

char * fetchSecKey(const char * buf)
{
  char *key;
  char *keyBegin;
  char *flag="Sec-WebSocket-Key: ";
  int i=0, bufLen=0;

  key=(char *)malloc(WEB_SOCKET_KEY_LEN_MAX);
  memset(key,0, WEB_SOCKET_KEY_LEN_MAX);
  if(!buf)
    {
      return NULL;
    }
 
  keyBegin=strstr(buf,flag);
  if(!keyBegin)
    {
      return NULL;
    }
  keyBegin+=strlen(flag);

  bufLen=strlen(buf);
  for(i=0;i<bufLen;i++)
    {
      if(keyBegin[i]==0x0A||keyBegin[i]==0x0D)
	{
	  break;
	}
      key[i]=keyBegin[i];
    }
  
  return key;
}

char * computeAcceptKey(const char * buf)
{
  char * clientKey;
  char * serverKey; 
  char * sha1DataTemp;
  char * sha1Data;
  short temp;
  int i,n;
  const char * GUID="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
 

  if(!buf)
    {
      return NULL;
    }
  clientKey=(char *)malloc(LINE_MAX);
  memset(clientKey,0,LINE_MAX);
  
  • 14
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值