我对websocket有疑问。我有一个特殊的需求,所以,嗅探连续串口(rs485)并将任何数据发送到客户端。 我在互联网上找到了许多帮助,我的书面程序也能正常工作。 我有一个我无法解决的最后一个问题。通常服务器无缘无故地关闭所有客户端的连接并退出c程序。 我必须创建一个虚拟缓冲区以确保所有线程都有数据,因为一旦你读取了串口的缓冲区,它就会被清空。 Websocket服务器在C中,websocket客户端在php / js中。 对不起我糟糕的英语,我很抱歉。 这是我的客户:
var server_connection;
var rs485_connection;
var ping_serverconnection;
var ping_rs485connection
var sockethide=true;
window.addEventListener("beforeunload", function (e) { socketConnection_close(); });
function socketConnection_open() {
server_socketConnect();
rs485_socketConnect();
}
function server_socketConnect() {
server_connection = new WebSocket('ws://192.168.2.8:5000');
server_connection.onopen = function () { serverOpened(); console.log('SERVER Connected!');};
server_connection.onerror = function (error) { console.log('WebSocket Error ' + error); };
server_connection.onmessage = function(e) { serverReceive(e.data); };
server_connection.onclose = function(e) { serverClosed(); console.log('SERVER Disconnected!'); };
ping_serverconnection=setInterval(function() {server_connection.send("ping");},5000);
}
function rs485_socketConnect() {
rs485_connection = new WebSocket('ws://192.168.2.8:5001',"DomoProtocol");
rs485_connection.onopen = function () { rs485Opened(); console.log('RS485 Connected!'); /*server_socketConnect()*/;};
rs485_connection.onerror = function (error) { console.log('WebSocket Error ' + error); };
rs485_connection.onmessage = function(e) { rs485Receive(e.data); };
rs485_connection.onclose = function(e) { rs485Closed(); console.log('RS485 Disconnected!'); };
//ping_rs485connection=setInterval(function() {rs485_connection.send("ping");},10000);
}
function socketConnection_close() {
//clearInterval(ping_serverconnection);
clearInterval(ping_rs485connection);
//server_connection.send("exit");
rs485_connection.send("exit");
for(i=0;i<100000;i++);
rs485_connection.close(); rs485_connection='';
server_connection.close(); server_connection='';
}
function serverOpened() {
document.getElementById("serverlightid").src=urlbase+"/images/icons/green.png";
}
function rs485Opened() {
document.getElementById("rs485lightid").src=urlbase+"/images/icons/green.png";
}
function serverClosed() {
server_connection.close(); server_connection='';
document.getElementById("serverlightid").src=urlbase+"/images/icons/red.png";
//server_socketConnect();
}
function rs485Closed() {
rs485_connection.close(); rs485_connection='';
document.getElementById("rs485lightid").src=urlbase+"/images/icons/red.png";
}
function socketexpand() {
if (sockethide) {
document.getElementById("socketDivId").style.width="500px";
document.getElementById("socketDivId").style.height="400px";
document.getElementById("socketexpandid").style.display="none";
document.getElementById("sockethideid").style.display="inline";
sockethide=false;
} else {
document.getElementById("socketDivId").style.width="80px";
document.getElementById("socketDivId").style.height="25px";
document.getElementById("socketexpandid").style.display="inline";
document.getElementById("sockethideid").style.display="none";
sockethide=true;
}
}
// *******************************************************************************************************
function serverReceive(msg) { alert("Dato Ricevuto server:"+msg); }
function server_connection_send(msg) {
server_connection.send(msg);
var node = document.createElement("span");
var textnode = document.createTextNode(msg+" ");
node.appendChild(textnode);
document.getElementById("serversocketdivid").appendChild(node);
}
function rs485Receive(msg) {
//var content=document.getElementById("rs485socketdivid");
var node = document.createElement("span");
var textnode = document.createTextNode(msg+" ");
node.appendChild(textnode);
document.getElementById("rs485socketdivid").appendChild(node);
//alert("Dato Ricevuto 485:"+msg);
}
function rs485_connection_send(msg) {
rs485_connection.send(msg);
var node = document.createElement("span");
var textnode = document.createTextNode(msg+" ");
node.appendChild(textnode);
document.getElementById("serversocketdivid").appendChild(node);
}
这是我在c:
中的服务器#include<stdint.h>
#include<stdarg.h>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
//for threading , link with lpthread
#include<pthread.h>
//for SHA1 + BASE64
#include <openssl/sha.h>
const char *BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//for serial
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MAX_BUFFER 1000
#define DELAYTOSEND 1000000
#define MAX_CONNECTION 10
void *connection_handler(void *);
void *connection_handler_master(void *);
int serialBuffer[MAX_BUFFER];
long arg;
int main(int argc , char *argv[])
{
int socket_desc , new_socket , c , *new_sock, i;
struct sockaddr_in server , client;
char client_message[2000], query[200]="";
char *message, *token, *key;
unsigned char obuf[20];
unsigned char b64[100];
//thread MASTER
for(i=0;i<(MAX_BUFFER+1);i++) serialBuffer[i]=-1;
pthread_t sniffer_thread;
new_sock = malloc(1);
*new_sock = new_socket;
if( pthread_create( &sniffer_thread , NULL , connection_handler_master , (void*) new_sock) < 0) {
perror("Non posso creare il Thread MASTER");
return 1;
}
puts("Thread MASTER creato");
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1) {
printf("Impossibile creare un socket");
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET; //IPv4
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 5001 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0) {
puts("bind fallito");
return 1;
}
puts("bind OK");
//Listen
listen(socket_desc , MAX_CONNECTION);
//Accept and incoming connection
puts("In attesa di connessione...");
c = sizeof(struct sockaddr_in);
while( (new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) ) {
puts("Connessione accetata");
recv(new_socket, client_message , 2000 , 0);
token=strtok(client_message,"\r\n");
//DEBUG while(token) { printf( "--------->: %s\n", token ); token=strtok(NULL,"\r\n"); } printf("----------------------------------------\r\n");
while(token != NULL) {
if(!strncmp(token,"Sec-WebSocket-Key:",18)) break; //printf( "%s\n", token );
token=strtok(NULL,"\r\n");
}
key=strtok(token," ");
key=strtok(NULL," ");
strcat(key,"258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
SHA1(key,strlen(key),obuf);
base64_encode(obuf,20,b64,100);
printf( "KEY: %s\n", key );
printf( "B64: %s\n", b64 );
strcat(query,"HTTP/1.1 101 Switching Protocols\r\n");
strcat(query,"Upgrade: Websocket\r\n");
strcat(query,"Connection: Upgrade\r\n");
strcat(query,"Sec-Websocket-Protocol:DomoProtocol\r\n");
strcat(query,"Sec-WebSocket-Accept: ");
strcat(query,b64);
strcat(query,"\r\n\r\n");
//DEBUG puts(token);
printf( "%s\n", query );
write(new_socket , query , strlen(query));
query[0]='\0';
pthread_t sniffer_thread;
new_sock = malloc(1);
*new_sock = new_socket;
if( pthread_create( &sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0) {
perror("Non posso creare il thread");
return 1;
}
puts("Thread creato, Handler assegnato");
printf("new_sock:%i\r\n",new_sock);
}
if (new_socket<0) {
perror("Connessione rifiutata");
return 1;
}
puts("uscita1");
return 0;
}
/**
* encode three bytes using base64 (RFC 3548)
*/
void _base64_encode_triple(unsigned char triple[3], char result[4]) {
int tripleValue, i;
tripleValue = triple[0];
tripleValue *= 256;
tripleValue += triple[1];
tripleValue *= 256;
tripleValue += triple[2];
for (i=0; i<4; i++) { result[3-i] = BASE64_CHARS[tripleValue%64]; tripleValue /= 64; }
}
/**
* encode an array of bytes using Base64 (RFC 3548)
* return 1 on success, 0 otherwise
*/
int base64_encode(unsigned char *source, size_t sourcelen, char *target, size_t targetlen) {
if ((sourcelen+2)/3*4 > targetlen-1) return 0;
/* encode all full triples */
while (sourcelen >= 3) {
_base64_encode_triple(source, target);
sourcelen -= 3;
source += 3;
target += 4;
}
if (sourcelen > 0) {
unsigned char temp[3];
memset(temp, 0, sizeof(temp));
memcpy(temp, source, sourcelen);
_base64_encode_triple(temp, target);
target[3] = '=';
if (sourcelen == 1) target[2] = '=';
target += 4;
}
target[0] = 0;
return 1;
}
/**
* determine the value of a base64 encoding character
* return the value in case of success (0-63), -1 on failure
*/
int _base64_char_value(char base64char) {
if (base64char >= 'A' && base64char <= 'Z') return base64char-'A';
if (base64char >= 'a' && base64char <= 'z') return base64char-'a'+26;
if (base64char >= '0' && base64char <= '9') return base64char-'0'+2*26;
if (base64char == '+') return 2*26+10;
if (base64char == '/') return 2*26+11;
return -1;
}
/**
* decode a 4 char base64 encoded byte triple
* return lenth of the result (1, 2 or 3), 0 on failure
*/
int _base64_decode_triple(char quadruple[4], unsigned char *result) {
int i, triple_value, bytes_to_decode = 3, only_equals_yet = 1;
int char_value[4];
for (i=0; i<4; i++) char_value[i] = _base64_char_value(quadruple[i]);
for (i=3; i>=0; i--) {
if (char_value[i]<0) {
if (only_equals_yet && quadruple[i]=='=') {
char_value[i]=0;
bytes_to_decode--;
continue;
}
return 0;
}
only_equals_yet = 0;
}
if (bytes_to_decode < 0) bytes_to_decode = 0;
triple_value = char_value[0]; triple_value *= 64;
triple_value += char_value[1]; triple_value *= 64;
triple_value += char_value[2]; triple_value *= 64;
triple_value += char_value[3];
for (i=bytes_to_decode; i<3; i++) triple_value /= 256;
for (i=bytes_to_decode-1; i>=0; i--) { result[i] = triple_value%256; triple_value /= 256; }
return bytes_to_decode;
}
/**
* decode base64 encoded data
* return length of converted data on success, -1 otherwise
*/
size_t base64_decode(char *source, unsigned char *target, size_t targetlen) {
char *src, *tmpptr;
char quadruple[4], tmpresult[3];
int i, tmplen = 3;
size_t converted = 0;
src = (char *)malloc(strlen(source)+5);
if (src == NULL) return -1;
strcpy(src, source);
strcat(src, "====");
tmpptr = src;
while (tmplen == 3) {
for (i=0; i<4; i++) {
while (*tmpptr != '=' && _base64_char_value(*tmpptr)<0) tmpptr++;
quadruple[i] = *(tmpptr++);
}
tmplen = _base64_decode_triple(quadruple, tmpresult);
if (targetlen < tmplen) { free(src); return -1; }
memcpy(target, tmpresult, tmplen);
target += tmplen;
targetlen -= tmplen;
converted += tmplen;
}
free(src);
return converted;
}
/*
* Serial Open
*/
int serialOpen (char *device, int baud) {
struct termios options ;
speed_t myBaud ;
int status, fd ;
if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1) return -1 ;
fcntl (fd, F_SETFL, O_RDWR) ;
tcgetattr (fd, &options) ;
cfmakeraw (&options) ;
cfsetispeed (&options, B115200) ;
cfsetospeed (&options, B115200) ;
options.c_cflag |= (CLOCAL | CREAD) ;
options.c_cflag &= ~PARENB ;
options.c_cflag &= ~CSTOPB ;
options.c_cflag &= ~CSIZE ;
options.c_cflag |= CS8 ;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
options.c_oflag &= ~OPOST ;
options.c_cc [VMIN] = 0 ;
options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds)
tcsetattr (fd, TCSANOW | TCSAFLUSH, &options) ;
ioctl (fd, TIOCMGET, &status);
status |= TIOCM_DTR ;
status |= TIOCM_RTS ;
ioctl (fd, TIOCMSET, &status);
usleep (10000) ; // 10mS
return fd ;
}
/*
* DECODE / ENCODE STRING TO BINARY
* */
char * decode( char *frame) {
static char text[2000];
int ofs=0, len=0, i=0, a=0;
len = (int)(frame[1]) & 127;
if (len == 126) { ofs = 8; }
else if (len == 127) { ofs = 14; }
else { ofs = 6; }
text[0] = '\0';
for (i = ofs; i < strlen(frame); i++) { text[a] = frame[i] ^ frame[ofs - 4 + (i - ofs) % 4]; a++; }
text[a] = '\0';
return text;
}
char * encode( char *frame) {
int indexStartRawData=-1, i=0;
long long int len=0;
static char bytesFormatted[2000];
for(i=0;i<2000;i++) bytesFormatted[i]='\0';
len = strlen(frame);
bytesFormatted[0]= 129;
if (len <= 125) {
bytesFormatted[1] = len;
indexStartRawData = 2;
} else if (len >= 126 && len <= 65535) {
bytesFormatted[1] = 126;
bytesFormatted[2] = ( len >> 8 ) && 255;
bytesFormatted[3] = ( len ) && 255;
indexStartRawData = 4;
} else {
bytesFormatted[1] = 127;
bytesFormatted[2] = ( len >> 56 ) && 255;
bytesFormatted[3] = ( len >> 48 ) && 255;
bytesFormatted[4] = ( len >> 40 ) && 255;
bytesFormatted[5] = ( len >> 32 ) && 255;
bytesFormatted[6] = ( len >> 24 ) && 255;
bytesFormatted[7] = ( len >> 16 ) && 255;
bytesFormatted[8] = ( len >> 8 ) && 255;
bytesFormatted[9] = ( len ) && 255;
indexStartRawData = 10;
}
strcat( bytesFormatted,frame);
bytesFormatted[indexStartRawData+len] ='\0';
return bytesFormatted;
}
char * asciiencode( int asciichar) {
int indexStartRawData=-1, i=0, len=0;
static char bytesFormatted[10];
static char asciiFormatted[10];
for(i=0;i<=6;i++) bytesFormatted[i]='\0';
sprintf(asciiFormatted,"%i\0",asciichar);
len = strlen(asciiFormatted);
bytesFormatted[0]= 129;
bytesFormatted[1] = len;
indexStartRawData = 2;
strcat( bytesFormatted,asciiFormatted);
bytesFormatted[indexStartRawData+len] =0;
bytesFormatted[indexStartRawData+len+1] =0;
bytesFormatted[indexStartRawData+len+2] ='\0';
//bytesFormatted[indexStartRawData+len] ='\r';
//bytesFormatted[indexStartRawData+len+1] ='\n';
return bytesFormatted;
}
/*
* Thread MASTER to popolate virtual array
* */
void *connection_handler_master (void *socket_desc) {
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size;
char *server_message , client_message[2000];
int i=0;
//Send some messages to the client
server_message = "Creazione MASTER avvenuta. ";
printf("%s\r\n",server_message);
server_message = "In attesa di dati sul bus RS485.";
printf("%s\r\n",server_message);
int handle;
uint8_t x ;
handle = serialOpen ("/dev/ttyAMA0", 115200) ;
//for(i=0;i<2001;i++) printf("%i: %i\r\n ",i,serialBuffer[i]);
while(1) {
while(!read (handle, &x, 1));
if(x>-1) {
serialBuffer[i]=x;
//DEBUG printf("%i-%i\r\n",i,serialBuffer[i]);
if(i==MAX_BUFFER) { serialBuffer[0]=-1; i=0; }
else { serialBuffer[i+1]=-1; i++; }
}
x=-1;
}
}
/*
* Thread clients
* */
void *connection_handler(void *socket_desc) {
//Get the socket descriptor
int sock = *(int*)socket_desc, read_size, i=0, a=0;
char *server_message , client_message[2000], *c;
//Send some messages to the client
server_message = "Connessione avvenuta. ";
write(sock , encode(server_message) , strlen(encode(server_message)));
server_message = "In attesa di dati sul buffer.";
write(sock , encode(server_message) , strlen(encode(server_message)));
//DEBUG printf("sock:%i\r\n",sock);
while(serialBuffer[i]!=-1) i++;
while(1) {
if(serialBuffer[i]!=-1) {
//DEBUG printf("Serialdata%i: %i\r\n",i,serialBuffer[i]);
server_message=asciiencode(serialBuffer[i]);
write(sock , server_message , strlen(server_message));
//printf("Serialdata--------------->%i: %s\r\n",i,server_message);
if(i==MAX_BUFFER) i=0;
else i++;
for(a=0;a<DELAYTOSEND;a++) { }
}
}
// This code is not used
//Receive a message from client
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 ) {
//Received message from client
//printf( "%s\n", decode(client_message) );
//send message to client
//server_message="provina";
//write(sock , encode(server_message) , strlen(encode(server_message)));
printf( "%s\n",decode(client_message));
//read (handle, &x, 1);
//sprintf(c,"%i",x);
//write (sock, encode(c),strlen(encode(c) ) );
printf("serialBUffer: %s\r\n",serialBuffer);
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
puts("uscita2");
perror("recv failed");
}
//Free the socket pointer
puts("uscita3");
free(socket_desc);
return 0;
}