java调用c wsdll,直接用C写一个websocket对接js的ws:websocket流程|时刻需 | 时刻需

本篇属于第五步

在第四步中我们已经可以简单的完成 socket的服务端及客户端,我本来想直接在windows上写一个客户端链接到linux上的服务端,但是由于目前完全是小白一个,在windows编译上遇到很多解决不了的问题所以决定暂时放弃这个工作(没有老师百度google也很无力)。

现在打算利用 js中的ws:websocket 来作为客户端,不多说了直接上流程及代码(参考git上的案例)

1.创建TCP链接类 文件名 tcp.c

#include

#include

#include

#include

#include

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);

///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;

}

2. 创建一个接口文件 tcp.h

#pragma once

extern int passive_server(int port,int queue);

3. 创建主类 main.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include "tcp.h"

#define BUFFER_SIZE 1024

#define RESPONSE_HEADER_LEN_MAX 1024

#define GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"

/*-------------------------------------------------------------------

0 1 2 3

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

+-+-+-+-+-------+-+-------------+-------------------------------+

|F|R|R|R| opcode|M| Payload len | Extended payload length |

|I|S|S|S| (4) |A| (7) | (16/64) |

|N|V|V|V| |S| | (if payload len==126/127) |

| |1|2|3| |K| | |

+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +

| Extended payload length continued, if payload len == 127 |

+ - - - - - - - - - - - - - - - +-------------------------------+

| |Masking-key, if MASK set to 1 |

+-------------------------------+-------------------------------+

| Masking-key (continued) | Payload Data |

+-------------------------------- - - - - - - - - - - - - - - - +

: Payload Data continued ... :

+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +

| Payload Data continued ... |

+---------------------------------------------------------------+

--------------------------------------------------------------------*/

typedef struct _frame_head {

char fin;

char opcode;

char mask;

unsigned long long payload_length;

char masking_key[4];

}frame_head;

int base64_encode(char *in_str, int in_len, char *out_str)

{

BIO *b64, *bio;

BUF_MEM *bptr = NULL;

size_t size = 0;

if (in_str == NULL || out_str == NULL)

return -1;

b64 = BIO_new(BIO_f_base64());

bio = BIO_new(BIO_s_mem());

bio = BIO_push(b64, bio);

BIO_write(bio, in_str, in_len);

BIO_flush(bio);

BIO_get_mem_ptr(bio, &bptr);

memcpy(out_str, bptr->data, bptr->length);

out_str[bptr->length-1] = '\0';

size = bptr->length;

BIO_free_all(bio);

return size;

}

/**

* @brief _readline

* read a line string from all buffer

* @param allbuf

* @param level

* @param linebuf

* @return

*/

int _readline(char* allbuf,int level,char* linebuf)

{

int len = strlen(allbuf);

for (;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);

// 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",sec_accept);

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;

}

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],temp;

int i;

if (read(fd,extern_len,8)<=0)

{

perror("read extern_len");

return -1;

}

for(i=0;i<4;i++)

{

temp = extern_len[i];

extern_len[i] = extern_len[7-i];

extern_len[7-i] = temp;

}

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;

}

/**

* @brief umask

* xor decode

* @param data

* @param len

* @param mask

*/

void umask(char *data,int len,char *mask)

{

int i;

for (i=0;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

{

//no code

response_head = (char*)malloc(12);

// response_head[0] = 0x81;

// response_head[1] = 127;

// response_head[2] = (head->payload_length >> 8 & 0xFF);

// response_head[3] = (head->payload_length & 0xFF);

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(9527,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);

int count = 10;

while (count--)

{

frame_head head;

int rul = recv_frame_head(conn,&head);

if (rul < 0)

break;

printf("fin=%d\nopcode=0x%X\nmask=%d\npayload_len=%llu\n",head.fin,head.opcode,head.mask,head.payload_length);

//echo head

send_frame_head(conn,&head);

//read payload data

char payload_data[1024] = {0};

int size = 0;

do {

int rul;

rul = read(conn,payload_data,1024);

if (rul<=0)

break;

size+=rul;

umask(payload_data,size,head.masking_key);

printf("recive:%s",payload_data);

//echo data

if (write(conn,payload_data,rul)<=0)

break;

}while(size

printf("\n-----------\n");

}

close(conn);

close(ser_fd);

}

3.编译前,先安装 libssl-dev

yum -y install libssl-dev

提示不需要任何更新(奇葩),但不知道为什么

只有手动安装了

下载源代码  下载地址

解压 tar -zxvf openssl-1.0.2q.tar

进入目录 cd openssl-1.0.2q

配置  ./config

安装 make install

默认会安装在 /usr/local/ssl 中

这个算作一个静态库 不要覆盖系统库以防破坏系统本身

安装成功后 查看 /usr/local/ssl/lib/ 是否有 libcrypto.a libssl.a这两个文件,如果存在则说明安装成功

4.编译

gcc main.c tcp.c -o server -I /usr/local/ssl/include -L /usr/local/ssl/lib -lssl -lcrypto

5.运行

./server

查看是否开启  netstat -tnl

tcp 0 0 0.0.0.0:9527 0.0.0.0:* LISTEN

看到 9527端口已经开启

6.客户端  client.html

connect

send

function svc_connectPlatform() {

//alert("");

var wsServer = 'ws://103.94.181.37:9527/';

try {

svc_websocket = new WebSocket(wsServer);

} catch (evt) {

console.log("new WebSocket error:" + evt.data);

svc_websocket = null;

if (typeof(connCb) != "undefined" && connCb != null)

connCb("-1", "connect error!");

return;

}

//alert("");

svc_websocket.onopen = svc_onOpen;

svc_websocket.onclose = svc_onClose;

svc_websocket.onmessage = svc_onMessage;

svc_websocket.onerror = svc_onError;

}

function svc_onOpen(evt) {

console.log("Connected to WebSocket server.");

}

function svc_onClose(evt) {

console.log("Disconnected");

}

function svc_onMessage(evt) {

console.log('Retrieved data from server: ' + evt.data);

}

function svc_onError(evt) {

console.log('Error occured: ' + evt.data);

}

function svc_send(msg) {

if (svc_websocket.readyState == WebSocket.OPEN) {

svc_websocket.send(msg);

} else {

console.log("send failed. websocket not open. please check.");

}

}

开启服务端后,在用google浏览器打开 client.html 查看console.log的情况

效果图

66.png

其中很重要的是握手协议  参考网站

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值