#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*在握手时需要进行sha1编码和base64编码,
在这里用openssl的库来实现*/
#if 0
#include <openssl/sha.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include "openssl/evp.h"
#else
#include "openssl/sha.h"
#include "openssl/pem.h"
#include "openssl/bio.h"
#include "openssl/evp.h"
#endif
//#include "base64.h"
#define BUFFER_SIZE 1024
#define RESPONSE_HEADER_LEN_MAX 1024
#define GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
typedef struct _frame_head {
char fin;
char opcode;
char mask;
unsigned long long payload_length;
char masking_key[4];
} frame_head;
int passive_server(int port,int queue)
{
///定义sockfd
int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);
///定义sockaddr_in
struct sockaddr_in server_sockaddr;
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_port = htons(port);
server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int reuse = 0;
setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int));
///bind,成功返回0,出错返回-1
if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1)
{
perror("bind");
exit(1);
}
///listen,成功返回0,出错返回-1
if(listen(server_sockfd,queue) == -1)
{
perror("listen");
exit(1);
}
printf("监听%d端口\n",port);
return server_sockfd;
}
unsigned char *base64_encode(unsigned char *str)
{
long len;
long str_len;
unsigned char *res;
int i,j;
//定义base64编码表
unsigned char *base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//计算经过base64编码后的字符串长度
str_len=SHA_DIGEST_LENGTH;//str_len=strlen(str);
if(str_len % 3 == 0)
len=str_len/3*4;
else
len=(str_len/3+1)*4;
res=malloc(sizeof(unsigned char)*len+1);
res[len]='\0';
//以3个8位字符为一组进行编码
for(i=0,j=0;i<len-2;j+=3,i+=4)
{
res[i]=base64_table[str[j]>>2]; //取出第一个字符的前6位并找出对应的结果字符
res[i+1]=base64_table[(str[j]&0x3)<<4 | (str[j+1]>>4)]; //将第一个字符的后位与第二个字符的前4位进行组合并找到对应的结果字符
res[i+2]=base64_table[(str[j+1]&0xf)<<2 | (str[j+2]>>6)]; //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符
res[i+3]=base64_table[str[j+2]&0x3f]; //取出第三个字符的后6位并找出结果字符
}
switch(str_len % 3)
{
case 1:
res[i-2]='=';
res[i-1]='=';
break;
case 2:
res[i-1]='=';
break;
}
return res;
}
int _readline(char* allbuf,int level,char* linebuf)
{
int len = strlen(allbuf);
for (;level<len;++level)
{
if(allbuf[level]=='\r' && allbuf[level+1]=='\n')
return level+2;
else
*(linebuf++) = allbuf[level];
}
return -1;
}
int shakehands(int cli_fd)
{
//next line's point num
int level = 0;
//all request data
char buffer[BUFFER_SIZE];
//a line data
char linebuf[256];
//Sec-WebSocket-Accept
char sec_accept[32];
//sha1 data
unsigned char sha1_data[SHA_DIGEST_LENGTH+1]={0};
//reponse head buffer
char head[BUFFER_SIZE] = {0};
if (read(cli_fd,buffer,sizeof(buffer))<=0)
perror("read");
printf("request\n");
printf("%s\n",buffer);
do {
memset(linebuf,0,sizeof(linebuf));
level = _readline(buffer,level,linebuf);
//printf("line:%s\n",linebuf);
if (strstr(linebuf,"Sec-WebSocket-Key")!=NULL)
{
strcat(linebuf,GUID);
// printf("key:%s\nlen=%d\n",linebuf+19,strlen(linebuf+19));
SHA1((unsigned char*)&linebuf+19,strlen(linebuf+19),(unsigned char*)&sha1_data);
// printf("sha1:%s\n",sha1_data);
//base64_encode(sha1_data,strlen(sha1_data),sec_accept);
//sec_accept = base64_encode(sha1_data);
// printf("base64:%s\n",sec_accept);
/* write the response */
sprintf(head, "HTTP/1.1 101 Switching Protocols\r\n" \
"Upgrade: websocket\r\n" \
"Connection: Upgrade\r\n" \
"Sec-WebSocket-Accept: %s\r\n" \
"\r\n",base64_encode(sha1_data));
printf("response\n");
printf("%s",head);
if (write(cli_fd,head,strlen(head))<0)
perror("write");
break;
}
}while((buffer[level]!='\r' || buffer[level+1]!='\n') && level!=-1);
return 0;
}
void inverted_string(char *str,int len)
{
int i; char temp;
for (i=0;i<len/2;++i)
{
temp = *(str+i);
*(str+i) = *(str+len-i-1);
*(str+len-i-1) = temp;
}
}
int recv_frame_head(int fd,frame_head* head)
{
char one_char;
/*read fin and op code*/
if (read(fd,&one_char,1)<=0)
{
perror("read fin");
return -1;
}
head->fin = (one_char & 0x80) == 0x80;
head->opcode = one_char & 0x0F;
if (read(fd,&one_char,1)<=0)
{
perror("read mask");
return -1;
}
head->mask = (one_char & 0x80) == 0X80;
/*get payload length*/
head->payload_length = one_char & 0x7F;
if (head->payload_length == 126)
{
char extern_len[2];
if (read(fd,extern_len,2)<=0)
{
perror("read extern_len");
return -1;
}
head->payload_length = (extern_len[0]&0xFF) << 8 | (extern_len[1]&0xFF);
}
else if (head->payload_length == 127)
{
char extern_len[8];
if (read(fd,extern_len,8)<=0)
{
perror("read extern_len");
return -1;
}
inverted_string(extern_len,8);
memcpy(&(head->payload_length),extern_len,8);
}
/*read masking-key*/
if (read(fd,head->masking_key,4)<=0)
{
perror("read masking-key");
return -1;
}
return 0;
}
void umask(char *data,int len,char *mask)
{
int i;
for (i=0;i<len;++i)
*(data+i) ^= *(mask+(i%4));
}
int send_frame_head(int fd,frame_head* head)
{
char *response_head;
int head_length = 0;
if(head->payload_length<126)
{
response_head = (char*)malloc(2);
response_head[0] = 0x81;
response_head[1] = head->payload_length;
head_length = 2;
}
else if (head->payload_length<0xFFFF)
{
response_head = (char*)malloc(4);
response_head[0] = 0x81;
response_head[1] = 126;
response_head[2] = (head->payload_length >> 8 & 0xFF);
response_head[3] = (head->payload_length & 0xFF);
head_length = 4;
}
else
{
response_head = (char*)malloc(12);
response_head[0] = 0x81;
response_head[1] = 127;
memcpy(response_head+2,&head->payload_length,sizeof(unsigned long long));
inverted_string(response_head+2,sizeof(unsigned long long));
head_length = 12;
}
if(write(fd,response_head,head_length)<=0)
{
perror("write head");
return -1;
}
free(response_head);
return 0;
}
int main()
{
int ser_fd = passive_server(4444,20);
struct sockaddr_in client_addr;
socklen_t addr_length = sizeof(client_addr);
int conn = accept(ser_fd,(struct sockaddr*)&client_addr, &addr_length);
shakehands(conn);
while (1)
{
frame_head head;
int rul = recv_frame_head(conn,&head);
if (rul < 0)
break;
// printf("fin=%d\nopcode=0x%X
没有合适的资源?快使用搜索试试~ 我知道了~
C语言实现的websocket
共4个文件
bak:1个
html:1个
websocket:1个
需积分: 50 71 下载量 25 浏览量
2020-11-18
16:16:47
上传
评论 1
收藏 9KB RAR 举报
温馨提示
该资源用C语言实现的简易websocket测试程序,并附有web端的html页面辅助调试,供websocket学习者下载使用,理解websocket协议
资源详情
资源评论
资源推荐
收起资源包目录
websocket.rar (4个子文件)
websocket
websocket 18KB
websocket.html 1KB
websocket.html.bak 1KB
websocket.c 9KB
共 4 条
- 1
yebour
- 粉丝: 6
- 资源: 2
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0