-
2021-05-17 14:49:47
客户端和服务器实现全双工通信(基于线程)
1、
基于多线程实现一个服务器和一个客户端实现全双工通信
服务器端创建两个线程:一个用于接收客户端发送过来的信息;一个用来给客户端发送信息。
客户端也创建两个线程:一个用于接收服务器端发送过来的信息;一个用来给服务器端发送信息。
2、
示例代码
服务器端的代码client.c
#include
#include
#include
#include
#include
#include
#include
#include
#define SERVPORT
3333
#define BACKLOG
10 //请求队列中的最大请求数
#define MAX_CONNECTED_NO
10 //最大是128台电脑连接
#define MAXDATASIZE
100
void pthread_recv(void
*arg);
void Pthread_send(void *
arg);
int main()
{
struct sockaddr_in server_sockaddr,client_sockaddr;
int sockfd,client_fd,sin_size,ret;
pthread_t id1,id2;
sin_size =sizeof(struct sockaddr);
//struct sockaddr_in server_sockaddr,client_sockaddr;
//建立一个socket连接
//目前都是AF_INET(ipv4);SOCK_STREAM(TCP),如果是UDP,则SOCK_DGRAM
if((sockfd = socket(AF_INET,SOCK_STREAM,0))==-1){
perror("socket");
exit(1);
}
printf("socket success!,sockfd=%d\n",sockfd);
//bind用于本地IP地址和端口的绑定
server_sockaddr.sin_family=AF_INET;
server_sockaddr.sin_port=htons(SERVPORT);
server_sockaddr.sin_addr.s_addr=INADDR_ANY;
//htonl(INADDR_ANY)
bzero(&(server_sockaddr.sin_zero),8);
//把本端的信息绑定
if(bind(sockfd,(struct sockaddr
*)&server_sockaddr,sizeof(struct
sockaddr))==-1)
{
perror("bind");
exit(1);
}
printf("bind success!\n");
if(listen(sockfd,BACKLOG)==-1)
{
perror("listen");
exit(1);
}
printf("listening....\n");
//接受并保存客户端的信息
if((client_fd=accept(sockfd,(struct sockaddr
*)&client_sockaddr,&sin_size))==-1)
{
perror("accept");
exit(1);
}
printf("client_fd=%d",client_fd);
pthread_create(&id1,NULL,(void *)
pthread_recv,(void*)&client_fd);
if(ret != 0)
perror("pthread_recv creat");
ret=pthread_create(&id2,NULL,(void
*)Pthread_send,(void*)&client_fd);
if(ret != 0)
perror("Pthread_send creat");
pthread_join(id1,NULL);
pthread_join(id2,NULL);
close(sockfd);
}
//服务器发送线程
void Pthread_send(void *
arg)
{
int buf_len, client_fd,sendbytes;
char buf[MAXDATASIZE];
client_fd = *((int *)arg);
printf("server send: ");
while(1)
{
fgets(buf,MAXDATASIZE,stdin);
buf_len =sizeof(buf);
if((sendbytes = send(client_fd ,buf,buf_len,0))==-1)
{
perror("send");
exit(1);
}
if(!strncmp(buf,"end",3)) //只比较字符串的前三个字符
break;
sleep(2);
}
}
//服务器接收数据线程
void pthread_recv(void
*arg)
{
int buf_len, client_fd,recvbytes;
char buf[MAXDATASIZE];
client_fd = *((int *)arg);
//接收服务端发来的信息
while(1)
{
if((recvbytes = recv(client_fd ,buf,MAXDATASIZE,0))==-1)
{
perror("recv");
exit(1);
}
else
{
buf[recvbytes]=0;
printf("server received data from server is
:%s\n",buf);
if(!strncmp(buf,"end",3)) //只比较字符串前三个字符
break;
}
sleep(1);
}
}
客户端的代码:
#include
#include
#include
#include
#include
#include
#include
#include
#define SERVPORT
3333
#define MAXDATASIZE
100
void pthread_recv(void
*arg);
void Pthread_send(void *
arg);
main(int argc,char
*argv[]){
int sockfd,sin_size,ret;
struct hostent *host;
pthread_t id1,id2;
struct sockaddr_in
serv_addr; //套接字的地址结构
struct sockaddr_in server_sockaddr;
if(argc < 2)
{
fprintf(stderr,"Please enter the server's hostname!\n");
exit(1);
}
//AF_INET:使用的是IPV4
//SOCK_STREAM:流式套接字
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
perror("socket");
exit(1);
}
printf("sockfd=%d\n",sockfd);
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(SERVPORT);
//serv_addr.sin_addr=*((struct
in_addr *)host->h_addr);
//host->h_addr强制类型转换;建议直接使用下面的方法
serv_addr.sin_addr.s_addr=inet_addr(argv[1]); //"127.0.0.1"); Internet地址
bzero(&(serv_addr.sin_zero),8);
//连接
if(connect(sockfd,(struct sockaddr
*)&serv_addr,sizeof(struct
sockaddr))==-1)
{
perror("connect");
exit(1);
}
ret=pthread_create(&id1,NULL,(void
*)Pthread_send,(void*)&sockfd);
if(ret != 0)
perror("Pthread_send creat");
pthread_create(&id2,NULL,(void *)
pthread_recv,(void*)&sockfd);
if(ret != 0)
perror("pthread_recv creat");
pthread_join(id1,NULL);
pthread_join(id2,NULL);
close(sockfd);
}
//客户端发送数据线程
void Pthread_send(void *
arg)
{
int buf_len, sockfd,sendbytes;
char buf[MAXDATASIZE];
sockfd = *((int *)arg);
printf("client send: ");
while(1)
{
fgets(buf,MAXDATASIZE,stdin);
buf_len =sizeof(buf);
if((sendbytes = send(sockfd,buf,buf_len,0))==-1)
{
perror("send");
exit(1);
}
if(!strncmp(buf,"end",3)) //只比较字符串的前三个字符
break;
sleep(2);
}
}
//客户端接收数据线程
void pthread_recv(void
*arg)
{
int buf_len, sockfd,recvbytes;
char buf[MAXDATASIZE];
sockfd = *((int *)arg);
//接收服务端发来的信息
while(1)
{
if((recvbytes = recv(sockfd,buf,MAXDATASIZE,0))==-1)
{
perror("recv");
exit(1);
}
else
{
buf[recvbytes]=0;
printf("client received data from server is :%s\n",buf);
if(!strncmp(buf,"end",3)) //只比较字符串的前三个字符
break;
}
sleep(1);
}
}
2012年4月22日星期日
更多相关内容 -
Python socket实现多对多全双工通信的方法
2021-01-01 13:39:26服务器:#server.py #!/usr/bin/env python #-*-coding:utf-8-*- import sys import struct#将字符串打包为二进制流进行网络传输 import select# import signal#用于捕获中断信号 import cPickle#将python对象进行... -
java。Tcp 全双工通信
2018-03-21 21:44:31java socket tcp 全双工通信,使用多线程,使用命令行进行全双工通信 -
论文研究-全双工通信射频自干扰消除硬件实现 .pdf
2019-08-16 09:20:47全双工通信射频自干扰消除硬件实现,任宇鑫,于翠屏,本文在现有2.4GHz收发信机的基础上,针对点对点同时同频全双工通信,设计并研发了一套射频自干扰消除装置。本文设计的功率精确控制 -
基于STM32的SPI主从全双工通信源码,欢迎测试-电路方案
2021-04-22 07:39:14更正:我之前的两个时钟的理论是不合理的,因为全双工收发是可以共用时钟的,这个我在后面改进的主机程序中有体现。 欢迎大家测试 u8 SPI1_ReadByte(u8 TxData) { u8 retry=0; // while((SPI1->SR&1<<1>200)... -
基于嵌入式与单片机的485全双工通信设计实现
2022-04-09 10:05:30基于嵌入式与单片机的485全双工通信设计实现 -
Tcp全双工通信测试代码
2018-12-01 07:57:31该项目源码一两百行,测试了TCP的全双工通信,分享给大家 -
node-express-chat:Node.js和Socket.io使全双工通信变得容易(全2通,就像手机通话一样)
2021-05-03 20:23:51Node.js和Socket.io使全双工通信变得容易(全2通,就像手机通话一样) 链接 要求 浏览器(例如Chrome) 文本编辑器(例如VS Code) 响应式 好处 仍然不需要构建工具 Node.js非阻塞事件循环支持许多并发请求 Socket.... -
【开源】全双工通信 SPEEX 对讲机(原理图、PCB源文件、程序源码及例程)-电路方案
2021-04-22 01:38:50PCB是第一版,调教后忘记在PCB上改了,调教后的电路声音清晰,完全实现全双工通信。使用我提供的这版PCB也不影响使用,主要是在电源地方加个电解电容;在DA输出的地方运放周边的电阻阻值,电容容值要小改一下。懂... -
html5的websockets全双工通信详解学习示例
2020-09-28 01:52:15本文主要研究HTML5 WebSockets的使用方法,它是HTML5中最强大的通信功能,定义了一个全双工的通信信道,只需Web上的一个Socket即可进行通信,能减少不必要的网络流量并降低网络延迟。HTML5 WebSockets能使数据从几千... -
全双工通信 TCP服务器搭建
2017-08-29 23:36:32全双工通信 TCP服务器搭建,使用套接字,fork进程控制 实现全双工双向通信,将文件解压放到Linux中,运行服务器,在开发板Y运行客户端 -
TCP全双工通信
2017-07-06 14:22:59LabVIEW实现多上位机,单下位机的全双工TCP通讯。 -
用Winsock实现语音全双工通信使用
2021-05-21 08:02:30二、主要函数的使用要点通过建立双套接字,可以很方便地实现全双工网络通信。1.套接字建立函数:SOCKET socket(int family,int type,int protocol)对于UDP协议,写为:SOCKRET s;s=socket(AF_INET,SOCK_...二、主要函数的使用要点
通过建立双套接字,可以很方便地实现全双工网络通信。
1.套接字建立函数:
SOCKET socket(int family,int type,int protocol)
对于UDP协议,写为:
SOCKRET s;
s=socket(AF_INET,SOCK_DGRAM,0);
或s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)
为了建立两个套接字,必须实现地址的重复绑定,即,当一个套接字已经绑定到某本地地址后,为了让另一个套接字重复使用该地址,必须为调用bind()函数绑定第二个套接字之前,通过函数setsockopt()为该套接字设置SO_REUSEADDR套接字选项。通过函数getsockopt()可获得套接字选项设置状态。需要注意的是,两个套接字所对应的端口号不能相同。此外,还涉及到套接字缓冲区的设置问题,按规定,每个区的设置范围是:不小于512个字节,大大于8k字节,根据需要,文中选用了4k字节。
2.套接字绑定函数
int bind(SOCKET s,struct sockaddr_in*name,int namelen)
s是刚才创建好的套接字,name指向描述通讯对象的结构体的指针,namelen是该结构体的长度。该结构体中的分量包括:IP地址(对应name.sin_addr.s_addr)、端口号(name.sin_port)、地址类型(name.sin_family,一般都赋成AF_INET,表示是internet地址)。
(1)IP地址的填写方法:在全双工通信中,要把用户名对应的点分表示法地址转换成32位长整数格式的IP地址,使用inet_addr()函数。
(2)端口号是用于表示同一台计算机不同的进程(应用程序),其分配方法有两种:1)进程可以让系统为套接字自动分配一端口号,只要在调用bind前将端口号指定为0即可。由系统自动分配的端口号位于1024~5000之间,而1~1023之间的任一TCP或UDP端口都是保留的,系统不允许任一进程使用保留端口,除非其有效用户ID是零(超级用户)。
2)进程可为套接字指定一特定端口。这对于需要给套接字分配一众所端口的服务器是很有用的。指定范围为1024和65536之间。可任意指定。
在本程序中,对两个套接字的端口号规定为2000和2001,前者对应发送套接字,后者对应接收套接字。
端口号要从一个16位无符号数(u_short类型数)从主机字节顺序转换成网络字节顺序,使用htons()函数。
根据以上两个函数,可以给出双套接字建立与绑定的程序片断。
//设置有关的全局变量
SOCKET sr,ss;
HPSTR sockBufferS,sockBufferR;
HANDLE hSendData,hReceiveData;
DWROD dwDataSize=1024*4;
struct sockaddr_in therel.there2;
#DEFINE LOCAL_HOST_ADDR 200.200.200.201
#DEFINE REMOTE_HOST-ADDR 200.200.200.202
#DEFINE LOCAL_HOST_PORT 2000
#DEFINE LOCAL_HOST_PORT 2001
//套接字建立函数
BOOL make_skt(HWND hwnd)
{
struct sockaddr_in here,here1;
ss=socket(AF_INET,SOCK_DGRAM,0);
sr=socket(AF_INET,SOCK_DGRAM,0);
if((ss==INVALID_SOCKET)||(sr==INVALID_SOCKET))
{
MessageBox(hwnd,“套接字建立失败!”,“”,MB_OK);
return(FALSE);
}
here.sin_family=AF_INET;
here.sin_addr.s_addr=inet_addr(LOCAL_HOST_ADDR);
here.sin_port=htons(LICAL_HOST_PORT);
//another socket
herel.sin_family=AF_INET;
herel.sin_addr.s_addr(LOCAL_HOST_ADDR);
herel.sin_port=htons(LOCAL_HOST_PORT1);
SocketBuffer();//套接字缓冲区的锁定设置
setsockopt(ss,SOL_SOCKET,SO_SNDBUF,(char FAR*)sockBufferS,dwDataSize);
if(bind(ss,(LPSOCKADDR)&here,sizeof(here)))
{
MessageBox(hwnd,“发送套接字绑定失败!”,“”,MB_OK);
return(FALSE);
}
setsockopt(sr SQL_SOCKET,SO_RCVBUF|SO_REUSEADDR,(char FAR*)
sockBufferR,dwDataSize);
if(bind(sr,(LPSOCKADDR)&here1,sizeof(here1)))
{
MessageBox(hwnd,“接收套接字绑定失败!”,“”,MB_OK);
return(FALSE);
}
return(TRUE);
}
//套接字缓冲区设置
void sockBuffer(void)
{
hSendData=GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,dwDataSize);
if(!hSendData)
{
MessageBox(hwnd,“发送套接字缓冲区定位失败!”,NULL,
MB_OK|MB_ICONEXCLAMATION);
return;
}
if((sockBufferS=GlobalLock(hSendData)==NULL)
{
MessageBox(hwnd,“发送套接字缓冲区锁定失败!”,NULL,
MB_OK|MB_ICONEXCLAMATION);
GlobalFree(hRecordData[0];
return;
}
hReceiveData=globalAlloc(GMEM_MOVEABLE|GMEM_SHARE,dwDataSize);
if(!hReceiveData)
{
MessageBox(hwnd,"“接收套接字缓冲区定位败!”,NULL
MB_OK|MB_ICONEXCLAMATION);
return;
}
if((sockBufferT=Globallock(hReceiveData))=NULL)
MessageBox(hwnd,"发送套接字缓冲区锁定失败!”,NULL,
MB_OK|MB_ICONEXCLAMATION);
GlobalFree(hRecordData[0]);
return;
}
{
3.数据发送与接收函数;
int sendto(SOCKET s.char*buf,int len,int flags,struct sockaddr_in to,int
tolen);
int recvfrom(SOCKET s.char*buf,int len,int flags,struct sockaddr_in
fron,int*fromlen)
其中,参数flags一般取0。
recvfrom()函数实际上是读取sendto()函数发过来的一个数据包,当读到的数据字节少于规定接收的数目时,就把数据全部接收,并返回实际接收到的字节数;当读到的数据多于规定值时,在数据报文方式下,多余的数据将被丢弃。而在流方式下,剩余的数据由下recvfrom()读出。为了发送和接收数据,必须建立数据发送缓冲区和数据接收缓冲区。规定:IP层的一个数据报最大不超过64K(含数据报头)。当缓冲区设置得过多、过大时,常因内存不够而导致套接字建立失败。在减小缓冲区后,该错误消失。经过实验,文中选用了4K字节。
此外,还应注意这两个函数中最后参数的写法,给sendto()的最后参数是一个整数值,而recvfrom()的则是指向一整数值的指针。
4.套接字关闭函数:closesocket(SOCKET s)
通讯结束时,应关闭指定的套接字,以释与之相关的资源。
在关闭套接字时,应先对锁定的各种缓冲区加以释放。其程序片断为:
void CloseSocket(void)
{
GlobalUnlock(hSendData);
GlobalFree(hSenddata);
GlobalUnlock(hReceiveData);
GlobalFree(hReceiveDava);
if(WSAAysncSelect(ss,hwnd,0,0)=SOCKET_ERROR)
{
MessageBos(hwnd,“发送套接字关闭失败!”,“”,MB_OK);
return;
}
if(WSAAysncSelect(sr,hwnd,0,0)==SOCKET_ERROR)
{
MessageBox(hwnd,“接收套接字关闭失败!”,“”,MB_OK);
return;
}
WSACleanup();
closesockent(ss);
closesockent(sr);
return;
}
三、Winsock的编程特点与异步选择机制
1 阻塞及其处理方式
在网络通讯中,由于网络拥挤或一次发送的数据量过大等原因,经常会发生交换的数据在短时间内不能传送完,收发数据的函数因此不能返回,这种现象叫做阻塞。Winsock对有可能阻塞的函数提供了两种处理方式:阻塞和非阻塞方式。在阻塞方式下,收发数据的函数在被调用后一直要到传送完毕或者出错才能返回。在阻塞期间,被阻的函数不会断调用系统函数GetMessage()来保持消息循环的正常进行。对于非阻塞方式,函数被调用后立即返回,当传送完成后由Winsock给程序发一个事先约定好的消息。
在编程时,应尽量使用非阻塞方式。因为在阻塞方式下,用户可能会长时间的等待过程中试图关闭程序,因为消息循环还在起作用,所以程序的窗口可能被关闭,这样当函数从Winsock的动态连接库中返回时,主程序已经从内存中删除,这显然是极其危险的。
2 异步选择函数WSAAsyncSelect()的使用
Winsock通过WSAAsyncSelect()自动地设置套接字处于非阻塞方式。使用WindowsSockets实现Windows网络程序设计的关键就是它提供了对网络事件基于消息的异步存取,用于注册应用程序感兴趣的网络事件。它请求Windows Sockets DLL在检测到套接字上发生的网络事件时,向窗口发送一个消息。对UDP协议,这些网络事件主要为:
FD_READ 期望在套接字收到数据(即读准备好)时接收通知;
FD_WRITE 期望在套接字可发送数(即写准备好)时接收通知;
FD_CLOSE 期望在套接字关闭时接电通知
消息变量wParam指示发生网络事件的套接字,变量1Param的低字节描述发生的网络事件,高字包含错误码。如在窗口函数的消息循环中均加一个分支:
int ok=sizeof(SOCKADDR);
case wMsg;
switch(1Param)
{
case FD_READ:
//套接字上读数据
if(recvfrom(sr.lpPlayData[j],dwDataSize,0,(struct sockaddr FAR*)&there1,
(int FAR*)&ok)==SOCKET_ERROR0
{
MessageBox)hwnd,“数据接收失败!”,“”,MB_OK);
return(FALSE);
}
case FD_WRITE:
//套接字上写数据
}
break;
在程序的编制中,应根据需要灵活地将WSAAsyncSelect()函灵敏放在相应的消息循环之中,其它说明可参见文献[1]。此外,应该指出的是,以上程序片断中的消息框主要是为程序调试方便而设置的,而在正式产品中不再出现。同时,按照程序容错误设计,应建立一个专门的容错处理函数。程序中可能出现的各种错误都将由该函数进行处理,依据错误的危害程度不同,建立几种不同的处理措施。这样,才能保证双方通话的顺利和可靠。
四、结论
本文是多媒体网络传输项目的重要内容之一,目前,结合硬件全双工语音卡等设备,已经成功地实现了话音的全双工的通信。
-
基于CSMA的全双工无线通信MAC协议设计
2021-01-28 04:04:51针对现有全双工通信MAC协议静态配对的不足,本文提出一种动态自配对MAC协议设计方案。该方案能够增大全双工无线通信的建立几率,避免通信冲突,提升频带利用率。仿真结果表明,与传统的半双工无线通信进行比较,动态... -
一文了解websocket全双工通信java实现
2022-04-12 10:31:10一文了解websocket全双工通信java实现1.websocket介绍
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。1.1注解介绍
@ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端。 注解的值将被用于监听用户连接的终端访问URL地址。 @OnMessage 前端发送消息 进行处理 @OnClose 关闭处理 @OnOpen 前端打开页面的处理
2.demo
引入依赖:
compile group: 'org.springframework.boot', name: 'spring-boot-starter-websocket', version: '2.5.5'
2.1 后端代码
package com.zqm.utils.socket; /** * @describe: sid 需要提前约定 * @author:zqm */ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; @ServerEndpoint("/websocket/{sid}") @Component public class WebSocketTest { private static final ConcurrentHashMap<String, Session> SESSION_MAP = new ConcurrentHashMap(); /** * 接受消息 * @param sid * @param session * @throws IOException * @throws InterruptedException // @OnMessage // public void onMessage(@PathVariable("sid") String sid, Session session) // throws IOException, InterruptedException { // System.out.println(); // } */ /** * 接受消息 * * @param message 客户端发送的消息 * @param session * @throws IOException * @throws InterruptedException */ @OnMessage public void onMessage(String message, Session session) { System.out.println(session.getPathParameters().get("sid")); System.out.println(message); } /** * 登记连接 * * @param sid * @param session */ @OnOpen public void onOpen(@PathParam("sid") String sid, Session session) { if (SESSION_MAP.containsKey(sid)) { return; } SESSION_MAP.put(sid, session); System.out.println("Client connected"); } /** * 注销连接 */ c public void onClose() { System.out.println("Connection closed"); } public void sendMessage(String sid, String message) throws IOException { if (StringUtils.isNotBlank(sid)) { Session session = SESSION_MAP.get(sid); session.getBasicRemote().sendText(message); } } } package com.zqm.controller; import com.zqm.utils.socket.WebSocketTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; /** * @describe: * @author:zqm */ @RestController @RequestMapping("web-socket") public class WebSocketController { @Autowired private WebSocketTest webSocketTest; @RequestMapping("send") public void sendMessage(String message) throws IOException { webSocketTest.sendMessage("user000",message); } }
2.2 前端代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> Websocket Demo <br /> <input id="text" type="text" /> <button onclick="send()"> Send </button> <button onclick="closeWebSocket()"> Close </button> <div id="message"> </div> <script type="text/javascript"> //判断当前浏览器是否支持WebSocket if('WebSocket' in window){ websocket = new WebSocket("ws://192.168.43.12:8081/zqm/websocket/user"); console.log("link success") }else{ alert('Not support websocket') } //连接发生错误的回调方法 websocket.onerror = function(){ setMessageInnerHTML("error"); }; //连接成功建立的回调方法 websocket.onopen = function(event){ setMessageInnerHTML("open"); } console.log("-----") //接收到消息的回调方法 websocket.onmessage = function(event){ setMessageInnerHTML(event.data); } //连接关闭的回调方法 websocket.onclose = function(){ setMessageInnerHTML("close"); } //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function(){ websocket.close(); } //将消息显示在网页上 function setMessageInnerHTML(innerHTML){ document.getElementById('message').innerHTML += innerHTML + '<br/>'; } //关闭连接 function closeWebSocket(){ websocket.close(); } //发送消息 function send(){ var message = document.getElementById('text').value; websocket.send(message); } </script> </body> </html>
2.3 效果
1.先启动后端服务,打开html,显示连接成功
2.客户端发送消息,后台接受成功
3.后台发送消息,客户端接受成功
-
使用WebSocket进行全双工通信
2021-05-22 04:22:56一、WebSocket简介WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,...一、WebSocket简介
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
二、WebSocket 通信原理
为了实现 WebSocket 通信,在 HTTP 连接建立之后,需要完成一 次“握手”(Handshaking)的步骤。
握手·请求
为了实现 WebSocket 通信,需要用到 HTTP 的 Upgrade 首部字 段,告知服务器通信协议发生改变,以达到握手的目的。
请求.jpg
Sec-WebSocket-Key 字段内记录着握手过程中必不可少的键值。 Sec-WebSocket-Protocol 字段内记录使用的子协议。 子协议按 WebSocket 协议标准在连接分开使用时,定义那些连接 的名称。
177 握手·响应
对于之前的请求,返回状态码 101 Switching Protocols 的响应。
响应.jpg
Sec-WebSocket-Accept 的字段值是由握手请求中的 SecWebSocket-Key 的字段值生成的。 成功握手确立 WebSocket 连接之后,通信时不再使用 HTTP 的数 据帧,而采用 WebSocket 独立的数据帧。
成功握手确立 WebSocket 连接之后,通信时不再使用 HTTP 的数 据帧,而采用 WebSocket 独立的数据帧。
通信原理图.jpg
JavaScript 可调用“The WebSocket API”,以下为调用 WebSocket API,每 50ms 发送一次数据的实例。
var socket = new WebSocket('ws://game.example.com:12010/updates');
socket.onopen = function () {
setInterval(function() {
if (socket.bufferedAmount == 0)
socket.send(getUpdateData());
}, 50);
};
-
485全双工通信
2010-10-10 12:59:01485全双工通信 -
java socket实现全双工通信
2021-02-12 22:29:29下面来看看一看这个认证的工作过程:第一步: 客户端发送http request 给服务器,服务器验证该用户是否已经登录验证过了,如果没有的话,服务器会返回一个401 Unauthozied给客户端,并且在Response 的 header ... -
485全双工通信.zip
2022-01-14 22:54:41485全双工通信.zip -
基于TLK2711的高速串行全双工通信协议研究
2021-01-30 13:00:36针对实时型相机对系统小型化、通用化及数据高速率可靠传输的需求,文中在研究高速串行器/解串器(SerDes)器件TLK2711工作原理的基础上,提出了高速串行全双工通信协议总体设计方案。文章以TLK2711为物理层、FPGA为... -
PC机与PIC单片机串行全双工通信.docx-综合文档
2021-05-20 19:58:26PC机与PIC单片机串行全双工通信.docx -
JAVA SOCKET实现全双工通信
2020-09-13 10:08:08客户端: public class MyChatClient { public static void main(String[] args) { try { InetAddress localHost = InetAddress.getLocalHost(); String hostAddress = localHost.getHostAddress();... -
51单片机的485全双工通信程序,程序简明,适合初学者使用
2012-08-29 11:52:2851单片机的485全双工通信程序,程序简明,适合初学者使用 -
全双工通信是什么意思?
2020-11-18 10:39:51RS-422标准就是全双工通信标准。全双工(Full Duplex)是 在微处理器与外围设备之间采用发送线和接受线各自独立的方法,可以使数据在两个方向上同时进行传送操作。指在发送数据的同时也能够接收数据,两者同步进行,... -
电容耦合功率传输系统共享通道上的全双工通信
2021-03-08 16:31:25本文针对电容耦合功率传输系统,提出了一种在共享信道上具有全双工通信的新型无线功率传输系统。 为了分析功率和信号传输,建立了功率和信号通道的频域模型。 基于该模型,分析了信道的信号传输特性以及功率流对信号... -
全双工通信的频谱有效双向解码转发中继
2021-03-31 23:14:40全双工通信的频谱有效双向解码转发中继 -
用Python多线程实现全双工通信
2020-07-25 19:09:37while True: msg=input("Python全双工通信测试,请输入发送信息:") tcpCliSock.send(msg.encode('utf-8')) ''' while True: data = tcpCliSock.recv(BUFSIZ) if not data: break #tcpCliSock.send('[%s] %s' %... -
webchat:websocket全双工通信聊天室demo
2021-05-21 02:31:49这是一个使用 node.js 编写的全双工通信聊天室,会话大厅已经完成,私聊 room 的细节还未完善,有空会继续编写。相关技术逻辑请查阅 体验成品小样: 部署步骤: 通过 安装生产环境 $ npm i 启动服务器 $ node server...