Socket(套接字)

CVAT自动标注避坑指南:从nuctl安装到YOLOv5模型部署的完整流程 本文详细介绍了在CVAT中部署YOLOv5自动标注功能的完整流程与避坑指南。重点解决了从nuctl工具安装、项目创建时因网络问题导致的镜像拉取失败,到最终模型函数部署与CVAT集成的关键步骤。针对国内网络环境,提供了实用的镜像替换方案,帮助用户顺利完成基于CPU的自动化标注环境搭建。 阅读详情

Socket(套接字)

 

◆先看定义:

typedef unsigned int u_int;
typedef u_int SOCKET;
◆Socket相当于进行网络通信两端的插座,只要对方的Socket和自己的Socket有通信联接,双方就可以发送和接收数据了。其定义类似于文件句柄的定义。

◆Socket有五种不同的类型:

1、流式套接字(stream socket)
定义:

#define SOCK_STREAM 1 
流式套接字提供了双向、有序的、无重复的以及无记录边界的数据流服务,适合处理大量数据。它是面向联结的,必须建立数据传输链路,同时还必须对传输的数据进行验证,确保数据的准确性。因此,系统开销较大。

2、 数据报套接字(datagram socket)

定义:

#define SOCK_DGRAM 2 
数据报套接字也支持双向的数据流,但不保证传输数据的准确性,但保留了记录边界。由于数据报套接字是无联接的,例如广播时的联接,所以并不保证接收端是否正在侦听。数据报套接字传输效率比较高。

3、原始套接字(raw-protocol interface)

定义:

#define SOCK_RAW 3 
原始套接字保存了数据包中的完整IP头,前面两种套接字只能收到用户数据。因此可以通过原始套接字对数据进行分析。
其它两种套接字不常用,这里就不介绍了。

◆Socket开发所必须需要的文件(以WinSock V2.0为例):

头文件:Winsock2.h

库文件:WS2_32.LIB

动态库:W32_32.DLL

 一些重要的定义

1、数据类型的基本定义:这个大家一看就懂。

typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;
2
、 网络地址的数据结构,有一个老的和一个新的的,请大家留意,如果想知道为什么,
请发邮件给Bill Gate。其实就是计算机的IP地址,不过一般不用用点分开的IP地
址,当然也提供一些转换函数。

◆ 旧的网络地址结构的定义,为一个4字节的联合:

struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
#define s_addr S_un.S_addr /* can be used for most tcp & ip code */
//
下面几行省略,反正没什么用处。
};
其实完全不用这么麻烦,请看下面:

◆ 新的网络地址结构的定义:
非常简单,就是一个无符号长整数 unsigned long。举个例子:IP地址为127.0.0.1的网络地址是什么呢?请看定义:

#define INADDR_LOOPBACK 0x7f000001
3
、 套接字地址结构

(1)、sockaddr结构:

struct sockaddr {
u_short sa_family; /* address family */
char sa_data[14]; /* up to 14 bytes of direct address */
};
sa_family
为网络地址类型,一般为AF_INET,表示该socket在Internet域中进行通信,该地址结构随选择的协议的不同而变化,因此一般情况下另一个与该地址结构大小相同的sockaddr_in结构更为常用,sockaddr_in结构用来标识TCP/IP协议下的地址。换句话说,这个结构是通用socket地址结构,而下面的sockaddr_in是专门针对Internet域的socket地址结构。

(2)、sockaddr_in结构

struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
sin _family
为网络地址类型,必须设定为AF_INET。sin_port为服务端口,注意不要使用已固定的服务端口,如HTTP的端口80等。如果端口设置为0,则系统会自动分配一个唯一端口。sin_addr为一个unsigned long的IP地址。sin_zero为填充字段,纯粹用来保证结构的大小。

◆ 将常用的用点分开的IP地址转换为unsigned long类型的IP地址的函数:

unsigned long inet_addr(const char FAR * cp )
用法:

unsigned long addr=inet_addr("192.1.8.84")
◆ 如果将sin_addr设置为INADDR_ANY,则表示所有的IP地址,也即所有的计算机。

#define INADDR_ANY (u_long)0x00000000
4
、 主机地址:

先看定义:

struct hostent {
char FAR * h_name; /* official name of host */
char FAR * FAR * h_aliases; /* alias list */
short h_addrtype; /* host address type */
short h_length; /* length of address */
char FAR * FAR * h_addr_list; /* list of addresses */
#define h_addr h_addr_list[0] /* address, for backward compat */
};
h_name
为主机名字。
h_aliases
为主机别名列表。
h_addrtype
为地址类型。
h_length
为地址类型。
h_addr_list
为IP地址,如果该主机有多个网卡,就包括地址的列表。
另外还有几个类似的结构,这里就不一一介绍了。

5、 常见TCP/IP协议的定义:

#define IPPROTO_IP 0 
#define IPPROTO_ICMP 1 
#define IPPROTO_IGMP 2 
#define IPPROTO_TCP 6 
#define IPPROTO_UDP 17 
#define IPPROTO_RAW 255 
具体是什么协议,大家一看就知道了。

 套接字的属性

为了灵活使用套接字,我们可以对它的属性进行设定。

1、 属性内容:

//允许调试输出
#define SO_DEBUG 0x0001 /* turn on debugging info recording */
//
是否监听模式
#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */
//
套接字与其他套接字的地址绑定
#define SO_REUSEADDR 0x0004 /* allow local address reuse */
//
保持连接
#define SO_KEEPALIVE 0x0008 /* keep connections alive */
//
不要路由出去
#define SO_DONTROUTE 0x0010 /* just use interface addresses */
//
设置为广播
#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */
//
使用环回不通过硬件
#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */
//
当前拖延值
#define SO_LINGER 0x0080 /* linger on close if data present */
//
是否加入带外数据
#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */
//
禁用LINGER选项
#define SO_DONTLINGER (int)(~SO_LINGER)
//
发送缓冲区长度
#define SO_SNDBUF 0x1001 /* send buffer size */
//
接收缓冲区长度
#define SO_RCVBUF 0x1002 /* receive buffer size */
//
发送超时时间
#define SO_SNDTIMEO 0x1005 /* send timeout */
//
接收超时时间
#define SO_RCVTIMEO 0x1006 /* receive timeout */
//
错误状态
#define SO_ERROR 0x1007 /* get error status and clear */
//
套接字类型
#define SO_TYPE 0x1008 /* get socket type */
2
、 读取socket属性:

int getsockopt(SOCKET s, int level, int optname, char FAR * optval, int FAR * optlen)
s
为欲读取属性的套接字。level为套接字选项的级别,大多数是特定协议和套接字专有的。如IP协议应为 IPPROTO_IP。

optname为读取选项的名称
optval
为存放选项值的缓冲区指针。
optlen
为缓冲区的长度
用法:

int ttl=0; //读取TTL值
int rc = getsockopt( s, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl));
//
来自MS platform SDK 2003
3
、 设置socket属性:

int setsockopt(SOCKET s,int level, int optname,const char FAR * optval, int optlen)
s
为欲设置属性的套接字。
level
为套接字选项的级别,用法同上。
optname
为设置选项的名称
optval
为存放选项值的缓冲区指针。
optlen
为缓冲区的长度

用法:

int ttl=32; //设置TTL值
int rc = setsockopt( s, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl));
 
套接字的使用步骤

1、启动Winsock:对Winsock DLL进行初始化,协商Winsock的版本支持并分配必要的
资源。(服务器端和客户端)

int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData )

wVersionRequested为打算加载Winsock的版本,一般如下设置:
wVersionRequested=MAKEWORD(2,0)
或者直接赋值:wVersionRequested=2

LPWSADATA为初始化Socket后加载的版本的信息,定义如下:
typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
} WSADATA, FAR * LPWSADATA;
如果加载成功后数据为:

wVersion=2表示加载版本为2.0。
wHighVersion
=514表示当前系统支持socket最高版本为2.2。
szDescription="WinSock 2.0"
szSystemStatus="Running"
表示正在运行。
iMaxSockets
=0表示同时打开的socket最大数,为0表示没有限制。
iMaxUdpDg
=0表示同时打开的数据报最大数,为0表示没有限制。
lpVendorInfo
没有使用,为厂商指定信息预留。
该函数使用方法:

WORD wVersion=MAKEWORD(2,0);
WSADATA wsData;
int nResult= WSAStartup(wVersion,&wsData);
if(nResult !=0)
{
//
错误处理
}
2
、创建套接字:(服务器端和客户端)

SOCKET socket( int af, int type, int protocol );
af
为网络地址类型,一般为AF_INET,表示在Internet域中使用。
type
为套接字类型,前面已经介绍了。
protocol
为指定网络协议,一般为IPPROTO_IP。
用法:

SOCKET sock=socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
if(sock==INVALID_SOCKET)
{
//
错误处理
}
3
、套接字的绑定:将本地地址绑定到所创建的套接字上。(服务器端和客户端)

int bind( SOCKET s, const struct sockaddr FAR * name, int namelen )
s
为已经创建的套接字。
name
为socket地址结构,为sockaddr结构,如前面讨论的,我们一般使用sockaddr_in
结构,在使用再强制转换为sockaddr结构。
namelen
为地址结构的长度。

用法:

sockaddr_in addr;
addr. sin_family=AF_INET;
addr. sin_port= htons(0); //
保证字节顺序
addr. sin_addr.s_addr= inet_addr("192.1.8.84")
int nResult=bind(s,(sockaddr*)&addr,sizeof(sockaddr));
if(nResult==SOCKET_ERROR)
{
//
错误处理
}
4
、 套接字的监听:(服务器端)

int listen(SOCKET s, int backlog )
s
为一个已绑定但未联接的套接字。
backlog
为指定正在等待联接的最大队列长度,这个参数非常重要,因为服务器一般可
以提供多个连接。
用法:

int nResult=listen(s,5) //最多5个连接
if(nResult==SOCKET_ERROR)
{
//
错误处理
}
5
、套接字等待连接::(服务器端)

SOCKET accept( SOCKET s, struct sockaddr FAR * addr, int FAR * addrlen )
s
为处于监听模式的套接字。
sockaddr
为接收成功后返回客户端的网络地址。
addrlen
为网络地址的长度。

用法:

sockaddr_in addr;
SOCKET s_d=accept(s,(sockaddr*)&addr,sizeof(sockaddr));
if(s==INVALID_SOCKET)
{
//
错误处理
}
6
、套接字的连结:将两个套接字连结起来准备通信。(客户端)

int connect(SOCKET s, const struct sockaddr FAR * name, int namelen )
s
为欲连结的已创建的套接字。
name
为欲连结的socket地址。
namelen
为socket地址的结构的长度。

用法:

sockaddr_in addr;
addr. sin_family=AF_INET;
addr. sin_port=htons(0); //
保证字节顺序
addr. sin_addr.s_addr= htonl(INADDR_ANY) //
保证字节顺序
int nResult=connect(s,(sockaddr*)&addr,sizeof(sockaddr));
if(nResult==SOCKET_ERROR)
{
//
错误处理
}
7
、套接字发送数据:(服务器端和客户端)

int send(SOCKET s, const char FAR * buf, int len, int flags )
s
为服务器端监听的套接字。
buf
为欲发送数据缓冲区的指针。
len
为发送数据缓冲区的长度。
flags
为数据发送标记。
返回值为发送数据的字符数。

◆这里讲一下这个发送标记,下面8中讨论的接收标记也一样:

flag取值必须为0或者如下定义的组合:0表示没有特殊行为。

#define MSG_OOB 0x1 /* process out-of-band data */
#define MSG_PEEK 0x2 /* peek at incoming message */
#define MSG_DONTROUTE 0x4 /* send without using routing tables */
MSG_OOB
表示数据应该带外发送,所谓带外数据就是TCP紧急数据。
MSG_PEEK
表示使有用的数据复制到缓冲区内,但并不从系统缓冲区内删除。
MSG_DONTROUTE
表示不要将包路由出去。

用法:

char buf[]="xiaojin";
int nResult=send(s,buf,strlen(buf));
if(nResult==SOCKET_ERROR)
{
//
错误处理
}
8
、 套接字的数据接收:(客户端)

int recv( SOCKET s, char FAR * buf, int len, int flags )
s
为准备接收数据的套接字。
buf
为准备接收数据的缓冲区。
len
为准备接收数据缓冲区的大小。
flags
为数据接收标记。
返回值为接收的数据的字符数。

用法:

char mess[1000];
int nResult =recv(s,mess,1000,0);
if(nResult==SOCKET_ERROR)
{
//
错误处理
}
9
、中断套接字连接:通知服务器端或客户端停止接收和发送数据。(服务器端和客户端)

int shutdown(SOCKET s, int how)
s
为欲中断连接的套接字。
How
为描述禁止哪些操作,取值为:SD_RECEIVE、SD_SEND、SD_BOTH。

#define SD_RECEIVE 0x00
#define SD_SEND 0x01
#define SD_BOTH 0x02
用法:

int nResult= shutdown(s,SD_BOTH);
if(nResult==SOCKET_ERROR)
{
//
错误处理
}
10
、 关闭套接字:释放所占有的资源。(服务器端和客户端)

int closesocket( SOCKET s )
s
为欲关闭的套接字。

用法:

int nResult=closesocket(s);
if(nResult==SOCKET_ERROR)
{
//
错误处理
}

与socket有关的一些函数介绍

1、读取当前错误值:每次发生错误时,如果要对具体问题进行处理,那么就应该调用这个函数取得错误代码。

      int  WSAGetLastError(void );

      #define h_errno   WSAGetLastError()

错误值请自己阅读Winsock2.h。

2
、将主机的unsigned long值转换为网络字节顺序(32位):为什么要这样做呢?因为不同的计算机使用不同的字节顺序存储数据。因此任何从Winsock函数对IP地址和端口号的引用和传给Winsock函数的IP地址和端口号均时按照网络顺序组织的。

      u_long  htonl(u_long hostlong);

      举例:htonl(0)=0

      htonl(80)= 1342177280

3、将unsigned long数从网络字节顺序转换位主机字节顺序,是上面函数的逆函数。

      u_long  ntohl(u_long netlong);

      举例:ntohl(0)=0

      ntohl(1342177280)= 80

4、将主机的unsigned short值转换为网络字节顺序(16位):原因同2:

      u_short  htons(u_short hostshort);

      举例:htonl(0)=0

      htonl(80)= 20480

5、将unsigned short数从网络字节顺序转换位主机字节顺序,是上面函数的逆函数。

      u_short  ntohs(u_short netshort);

      举例:ntohs(0)=0

      ntohsl(20480)= 80

6、将用点分割的IP地址转换位一个in_addr结构的地址,这个结构的定义见笔记(一),实际上就是一个unsigned long值。计算机内部处理IP地址可是不认识如192.1.8.84之类的数据。

      unsigned long  inet_addr( const char FAR * cp );

      举例:inet_addr("192.1.8.84")=1409810880

      inet_addr("127.0.0.1")= 16777343

如果发生错误,函数返回INADDR_NONE值。

7
、将网络地址转换位用点分割的IP地址,是上面函数的逆函数。

      char FAR *  inet_ntoa( struct in_addr in );

      举例:char * ipaddr=NULL;

      char addr[20];

      in_addr inaddr;

      inaddr. s_addr=16777343;

      ipaddr= inet_ntoa(inaddr);

      strcpy(addr,ipaddr);

这样addr的值就变为127.0.0.1。
注意意不要修改返回值或者进行释放动作。如果函数失败就会返回NULL值。

8
、获取套接字的本地地址结构:

      int  getsockname(SOCKET s, struct sockaddr FAR * name, int FAR * namelen );

      s为套接字

      name为函数调用后获得的地址值

      namelen为缓冲区的大小。

 

9、获取与套接字相连的端地址结构:

      int  getpeername(SOCKET s, struct sockaddr FAR * name, int FAR * namelen );

      s为套接字

      name为函数调用后获得的端地址值

      namelen为缓冲区的大小。

 

10、获取计算机名:

      int  gethostname( char FAR * name, int namelen );

      name是存放计算机名的缓冲区

      namelen是缓冲区的大小

      用法:

      char szName[255];

      memset(szName,0,255);

      if(gethostname(szName,255)==SOCKET_ERROR)

      {

               //错误处理

      }

      返回值为:szNmae="xiaojin"

 

11、根据计算机名获取主机地址:

      struct hostent FAR *  gethostbyname( const char FAR * name );

 

      name为计算机名。

      用法:

      hostent * host;

      char* ip;

      host= gethostbyname("xiaojin");

      if(host->h_addr_list[0])

      {

              struct in_addr addr;

          memmove(&addr, host->h_addr_list[0],4);

              //获得标准IP地址

              ip=inet_ ntoa (addr);

      }

 

      返回值为:hostent->h_name="xiaojin"

          hostent->h_addrtype=2    //AF_INET

          hostent->length=4

          ip="127.0.0.1"

Winsock 的I/O操作:


1、 两种I/O模式
阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序。套接字 默认为阻塞模式。可以通过多线程技术进行处理。
非阻塞模式:执行I/O操作时,Winsock函数会返回并交出控制权。这种模式使用起来比较复杂,因为函数在没有运行完成就进行返回,会不断地返回 WSAEWOULDBLOCK错误。但功能强大。
为了解决这个问题,提出了进行I/O操作的一些I/O模型,下面介绍最常见的三种:


2、select模型:
  通过调用select函数可以确定一个或多个套接字的状态,判断套接字上是否有数据,或
者能否向一个套接字写入数据。 int select( int nfds, fd_set FAR * readfds, fd_set FAR * writefds,
 fd_set FAR *exceptfds, const struct timeval FAR * timeout );


◆先来看看涉及到的结构的定义:
a、 d_set结构:
#define FD_SETSIZE 64?

typedef struct fd_set {
u_int fd_count; /* how many are SET? */
SOCKET fd_array[FD_SETSIZE]; /* an array of SOCKETs */
} fd_set;

fd_count为已设定socket的数量
fd_array为socket列表,FD_SETSIZE为最大socket数量,建议不小于64。这是微软建
议的。


B、timeval结构: struct timeval {
long tv_sec; /* seconds */

long tv_usec; /* and microseconds */
};

tv_sec为时间的秒值。
tv_usec为时间的毫秒值。
这个结构主要是设置select()函数的等待值,如果将该结构设置为(0,0),则select()函数
会立即返回。


◆再来看看select函数各参数的作用:
nfds:没有任何用处,主要用来进行系统兼容用,一般设置为0。
readfds:等待可读性检查的套接字组。
writefds;等待可写性检查的套接字组。
exceptfds:等待错误检查的套接字组。
timeout:超时时间。
函数失败的返回值:调用失败返回SOCKET_ERROR,超时返回0。
readfds、writefds、exceptfds三个变量至少有一个不为空,同时这个不为空的套接字组
种至少有一个socket,道理很简单,否则要select干什么呢。举例:测试一个套接字是否可读:fd_set fdread;
//FD_ZERO定义
// #define FD_ZERO(set) (((fd_set FAR *)(set))->fd_count=0)

FD_ZERO(&fdread);
FD_SET(s,&fdread); //加入套接字,详细定义请看winsock2.h
if(select(0,%fdread,NULL,NULL,NULL)>0
{

 //成功
 if(FD_ISSET(s,&fread) //是否存在fread中,详细定义请看winsock2.h
 {

 //是可读的
 }

}
◆I/O操作函数:主要用于获取与套接字相关的操作参数。
 int ioctlsocket(SOCKET s, long cmd, u_long FAR * argp );

s为I/O操作的套接字。
cmd为对套接字的操作命令。
argp为命令所带参数的指针。
常见的命令: //确定套接字自动读入的数据量
#define FIONREAD _IOR(''''f'''', 127, u_long) /* get # bytes to read */

//允许或禁止套接字的非阻塞模式,允许为非0,禁止为0
#define FIONBIO _IOW(''''f'''', 126, u_long) /* set/clear non-blocking i/o */

//确定是否所有带外数据都已被读入
#define SIOCATMARK _IOR(''''s'''', 7, u_long) /* at oob mark? */


3、WSAAsynSelect模型:
WSAAsynSelect模型也是一个常用的异步I/O模型。应用程序可以在一个套接字上接收以
WINDOWS消息为基础的网络事件通知。该模型的实现方法是通过调用WSAAsynSelect函
数 自动将套接字设置为非阻塞模式,并向WINDOWS注册一个或多个网络时间,并提供一
个通知时使用的窗口句柄。当注册的事件发生时,对应的窗口将收到一个基于消息的通知。
 int WSAAsyncSelect( SOCKET s, HWND hWnd, u_int wMsg, long lEvent);

s为需要事件通知的套接字
hWnd为接收消息的窗口句柄
wMsg为要接收的消息
lEvent为掩码,指定应用程序感兴趣的网络事件组合,主要如下: #define FD_READ_BIT 0
#define FD_READ (1 << FD_READ_BIT)

#define FD_WRITE_BIT 1
#define FD_WRITE (1 << FD_WRITE_BIT)
#define FD_OOB_BIT 2

#define FD_OOB (1 << FD_OOB_BIT)
#define FD_ACCEPT_BIT 3
#define FD_ACCEPT (1 << FD_ACCEPT_BIT)
#define FD_CONNECT_BIT 4
#define FD_CONNECT (1 << FD_CONNECT_BIT)
#define FD_CLOSE_BIT 5
#define FD_CLOSE (1 << FD_CLOSE_BIT)


用法:要接收读写通知:int nResult= WSAAsyncSelect(s,hWnd,wMsg,FD_READ|FD_WRITE);
if(nResult==SOCKET_ERROR)

{
 //错误处理
}

取消通知:
 int nResult= WSAAsyncSelect(s,hWnd,0,0);
当应用程序窗口hWnd收到消息时,wMsg.wParam参数标识了套接字,lParam的低字标明
了网络事件,高字则包含错误代码。


4、WSAEventSelect模型
WSAEventSelect模型类似WSAAsynSelect模型,但最主要的区别是网络事件发生时会被发
送到一个事件对象句柄,而不是发送到一个窗口。


使用步骤如下:
a、 创建事件对象来接收网络事件:
#define WSAEVENT HANDLE

#define LPWSAEVENT LPHANDLE
WSAEVENT WSACreateEvent( void );
该函数的返回值为一个事件对象句柄,它具有两种工作状态:已传信(signaled)和未传信
(nonsignaled)以及两种工作模式:人工重设(manual reset)和自动重设(auto reset)。默认未
未传信的工作状态和人工重设模式。


b、将事件对象与套接字关联,同时注册事件,使事件对象的工作状态从未传信转变未
已传信。
 int WSAEventSelect( SOCKET s,WSAEVENT hEventObject,long lNetworkEvents );

s为套接字
hEventObject为刚才创建的事件对象句柄
lNetworkEvents为掩码,定义如上面所述


c、I/O处理后,设置事件对象为未传信BOOL WSAResetEvent( WSAEVENT hEvent );
Hevent为事件对象
成功返回TRUE,失败返回FALSE。


d、等待网络事件来触发事件句柄的工作状态:
DWORD WSAWaitForMultipleEvents( DWORD cEvents,

const WSAEVENT FAR * lphEvents, BOOL fWaitAll,
DWORD dwTimeout, BOOL fAlertable );

lpEvent为事件句柄数组的指针
cEvent为为事件句柄的数目,其最大值为WSA_MAXIMUM_WAIT_EVENTS
fWaitAll指定等待类型:TRUE:当lphEvent数组重所有事件对象同时有信号时返回;
FALSE:任一事件有信号就返回。
dwTimeout为等待超时(毫秒)
fAlertable为指定函数返回时是否执行完成例程
对事件数组中的事件进行引用时,应该用WSAWaitForMultipleEvents的返回值,减去
预声明值WSA_WAIT_EVENT_0,得到具体的引用值。例如:
nIndex=WSAWaitForMultipleEvents(…);

MyEvent=EventArray[Index- WSA_WAIT_EVENT_0];
e、判断网络事件类型:


int WSAEnumNetworkEvents( SOCKET s,
WSAEVENT hEventObject, LPWSANETWORKEVENTS lpNetworkEvents );
s为套接字
hEventObject为需要重设的事件对象
lpNetworkEvents为记录网络事件和错误代码,其结构定义如下:
typedef struct _WSANETWORKEVENTS {

 long lNetworkEvents;
 int iErrorCode[FD_MAX_EVENTS];
} WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;
f、关闭事件对象句柄:
BOOL WSACloseEvent(WSAEVENT hEvent);

调用成功返回TRUE,否则返回FALSE。

基于 STM32 的便携式肌电信号采集与疲劳度评估系统设计与实现 本系统以 STM32 单片机为核心控制器,通过肌电电极采集人体骨骼肌表面的 sEMG 信号,经仪表放大、滤波、AD 采样后送入 MCU 进行时域 / 频域特征提取,利用 RMS(均方根)、MPF(中位频率)、MF(平均频率)等指标实时评估肌肉疲劳状态,最终通过 OLED 显示疲劳等级,并支持蓝牙上传至上位机。 阅读详情

相关推荐

电子结构设计(EMD)十年知识总结

客官,你的面相是做结构设计的奇才~1. 材料选择【一出手的0.1s就败了】2. 钣金件设计【折来折去有啥难】3. 塑胶件设计【看着好复杂】4. 型材件设计【凭啥不让我设计】5. 电子结构(PCBA)设计【静电肿么要我背锅】6. 包装设计【要的就是金玉其外,败絮其中】7. 外观(工业)设计【好不好看,谁说了算】8. 标签设计【】9. 标准件选择【一个螺丝难倒英雄汉/提起螺丝,英雄气短】10. 计算仿...

wfeng86的博客 1569

SOCKET 常用数据类型分析

1. SOCKET (套接字) typedef    UINT_PTR        SOCKET;typedef    unsigned int    UINT_PTR; 4个字节 2. sockaddr, SOCKADDR, PSOCKADDR (网络地址,通用)typedef    sockaddr    SOCKADDR, *PSOCKADDR; s

3889

深度解析:如何通过NodeRed实现私有485协议VRF中央空调与HomeAssistant的无缝对接

本文详细介绍了如何利用NodeRed的灵活流程化编程,破解并处理VRF中央空调的私有485协议,实现与HomeAssistant的无缝本地化集成。文章从协议分析、硬件准备到NodeRed核心流程搭建、数据映射及双向通信控制,提供了一套完整的实战方案,帮助用户将非标设备深度融入智能家居生态,摆脱对厂家云服务的依赖。

weixin_29173777的博客 407

看完之后保证你对socket编程步骤胸有成竹。 C++ Socket网络编程基础详解(TCP)

本文中我会根据windows下中使用C++以及socket进行网络编程的步骤,一步步的讲解网络编程的步骤,以及这些步骤中涉及到的定义,方法。力求你看完之后对socket编程步骤胸有成竹。

weixin_45704279的博客 5115

自动驾驶仿真:python和carsim联合仿真案例

carsim内部有许多相关联合仿真的demo,simulink、labview等等都有涉及,这里简单介绍下python和carsim联合仿真的方法,虽然carsim官方有个Steer_Control.py相关的案例,但是感觉比较冗余,这里抽出重点部分和大家交流探讨下。提示:以下是本篇文章正文内容,下面案例可供参考1、这里关于solvers的细节其实都没说,因为里面确实也没什么内容好讲的,本质就是调用carsim.dll,如果你需要更多的函数解析其实可以看vs_api.h,路径在,具体内容如下图所示。

zataji的博客 9060

免安装版Notepad++终极配置:右键菜单+图标美化+多文件批量处理(2024新版)

本文详细介绍了如何为免安装版Notepad++进行终极配置,包括右键菜单添加、图标美化以及多文件批量处理功能。通过注册表编辑和高级定制,用户可以在便携版中实现与安装版相同的功能体验,同时保持系统整洁。特别适合开发者、系统管理员和效率追求者使用。

nut55的博客 830

套接字类型 - socket type

1、数据流套接字(Stream Socket) 数据流式是一种面向连接的Socket,针对于面向连接的TCP服务应用,使用使用比较高质量的TCP协议。它有以下一些特点: (1) TCP提供可靠的连接。当TCP向另外一端发送数据时,它要求对方返回一个确认回答。如果没有收到确认,则会等待一段时间后重新发送,在数次重发失败后,TCP才会放弃发送。 (2) TCP为发送的数据进行排序。比

micx0124的专栏 2906

FAGLB03余额显示异常排查与修复指南

本文针对SAP新总账中FAGLB03报表余额显示异常问题,提供了专业的排查与修复指南。文章深入剖析了数据不一致的核心原因,如FAGLFLEXT汇总表与凭证明细不同步、年度余额结转(FAGLGVTR)失败等,并详细介绍了使用FAGLF03进行精准诊断、通过SE38执行标准调整程序TFC_ADJUST_VZ进行修复的标准操作流程,帮助用户快速恢复数据一致性,确保财务报表的准确性。

weixin_29313423的博客 307

套接字类型和协议设置

满足这2个条件的协议只有IPPROTO_TCP,因此可以如下调用socket函数创建套接字,这种套接字称为TCP套接字。另外,套接字中实际采用的最终协信息是通过socket 函数的第三个参数传递的。SOCK_DGRAM指的是面向消息的数据传输方式,满足上述条件的协议只有IPPROTO_UDP。因此,可以如下调用socket函数创建套接字,这种套接字称为UDP套接字。数据传输方式相同,但协议不同。“IPv4协议族中面向连接的套接字”“IPv4协议族中面向消息的套接字”:套接字中使用的协议族信息。

xiaobai_cpp的博客 829

YOLOv8的二次创新 | 结合iRMB与EMA打造全新的iEMA机制,提升动态检测性能【附保姆级代码】

YOLOv8继承了YOLO系列的轻量化和高效检测特性,同时通过改进的架构设计使得其在实时场景下具有更高的检测精度。然而,随着检测需求的增加,尤其是在动态目标检测和长时间序列检测中,YOLOv8的鲁棒性依然可以提升。通过iEMA机制的引入,我们将在这些方面进行进一步优化。iRMB模块是我们对传统Residual Block的进一步改进。通过多层特征提取,iRMB能够捕捉更多层次的特征信息,并通过引入轻量化的残差结构,提升计算效率。

一键难忘的博客 3085

C#利用最小二乘法拟合任意次函数曲线

给出一组离散点,确定一个函数逼近原函数,插值是这样的一种手段。在实际中,数据不可避免的会有误差,插值函数会将这些误差也包括在内。因此,我们需要一种新的逼近原函数的手段: ①不要求过所有的点(可以消除误差影响);②尽可能表现数据的趋势,靠近这些点。利用最小二乘法可以简便地求得未知的数据,并使得这些求得的数据与实际数据之间误差的平方和为最小 [1],其他一些优化问题也可通过最小化能量或最大化熵用最小二乘法来表达,具体可以查阅相关资料。最小二乘法(又称最小平方法)是一种数学技术。

qq_30725967的博客 3755

CAsyncSocket的用法

转载请注明出处blog.youkuaiyun.com/tianhai110这几天都在研么MFC的套接字类CAsyncSocket的用法, 将一些心得和实践中遇到的问题总结一下。 一、        一些网络的基本概念1.       同步:指的是发送方不等接收方响应,便接着发下个数据包的通信方式;2.       异步:指发送方发出数据后,等收到接收方发回的响应,才发下一个数据包的通信方式

greatsong的专栏 3490

16、AI与无人机助力紧急器官移植及医疗物资运输

本文探讨了AI与无人机(UAV)集成模型在紧急器官移植和医疗物资运输中的应用。传统运输方式受限于交通、时间和环境因素,而基于图神经网络(GNN)的AI-UAV系统可实现高效、智能、全天候的医疗物资配送,具备实时温湿度监控、自动导航和适应复杂地形等优势。文章分析了该模型在血液、器官运输中的关键作用,展示了其在澳大利亚、中国、美国等国的实际应用案例,并通过表格与流程图说明运作机制。同时,文章还探讨了技术、法规和社会层面的挑战及应对策略,展望了未来技术融合、应用拓展和国际合作的发展趋势,凸显其在全球医疗物流中的广

lll78的博客 102

【Python】Python 网络编程 ( Socket 套接字简介 | Socket 套接字使用步骤 | Socket 套接字服务端与客户端开发 )

一、Socket 套接字简介 1、Socket 套接字概念 2、Socket 套接字类型 3、Socket 套接字使用步骤 4、Socket 套接字服务端与客户端 二、Socket 服务端与客户端开发 1、服务端 2、客户端 3、执行结果

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 7730

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Socket套接字

DatagramSocket是UDP的Socket,用于发送和接收数据报,通过不同的构造方法,可以指定作为客户端还是服务端,客户端一般是不需要指定端口号,由操作系统分配,而服务端的端口号则需程序员指定,有了固定的端口号,方便为客户端服务。方法名方法说明创建一个UDP套接字的Socket,绑定到本机随机端口,由操作系统决定,一般用作客户端创建一个UDP套接字的Socket,绑定到本机指定端口,一般用作服务端此套接字发送数据报此套接字等待接收数据报,没有接收到会阻塞等待关闭套接字。

2301_80791093的博客 1118

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

[Linux网络编程]Socket套接字

socket 的原意是“插座”,在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。本文归纳整理Socket的使用

weixin_44972997的博客 3671

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

linux之套接字Socket

比如你只是想连接到一个远程主机上面进行通讯,你并不在乎你究竟是用的自己机器上的哪个端口进行通讯(比如 Telnet),那么你可以简单的直接调用 connect()函数,connect()将自动寻找出本地机器上的一个未使用的端口,然后调用 bind()来将其 socket 绑定到那个端口上。一个文件描述符只是一个简单的整型数值,代表一个被打开的文件(这里的文件是广义的文件,并不止代表不同的磁盘文件,他可以代表一个网络上的连接,一个先进先出队列,一个终端显示屏幕,以及其他一切)。允许你进行 login 操作。

2401_83157962的博客 985

Socket 套接字常用方法

本文详细介绍了Linux C++套接字编程中常用函数的核心参数和使用方法。主要内容包括: 基础数据类型(如套接字描述符int、地址结构sockaddr_in)和必要头文件 TCP套接字编程关键函数:socket()创建套接字、bind()绑定地址、listen()监听连接、accept()接受连接、connect()发起连接、send()/recv()数据传输 UDP套接字特有的sendto()和recvfrom()函数 各函数的参数详解、返回值说明及常见错误场景 网络字节序转换函数和特殊常量(如INADD

TTKunn的博客 1082

【网络】Socket套接字

本篇文章围绕计算机网络中的Socket套接字展开讲解,包含端口号、初识TCP/UDP协议、网络字节序、Socket套接字概念和常用API等内容

Eristic0618的博客 1483

Linux套接字Socket

Linux套接字Socket,从0开始学习

scq_king的博客 1486

套接字—Socket

网络编程就不得不提大名鼎鼎的套接字—Socket一,什么是Socket 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个Socket。Socket的英文原意是“插座”,通常称之为套接字,来描述IP地址和端口,是一个通信链的句柄,用来实现不同虚拟机或者计算机之间的通信。 在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个S

染尘 7875

什么是socket套接字?

客户端-服务器模型 互联网已经深入我们生活的方方面面,重要性不言而喻。上世纪70年代互联网刚发明的时候,就确定了客户端-服务器模型,这个编程模型一直沿用到现在都没有变过,我们在电脑上打开一个网站,在微信上聊天,打开一个app本质上都是客户端和服务器的连接和交互。 客户端-服务器模型的操作方式如下: (图片来源:极客时间) 客户端需要一个服务的时候,比如需要打开一个...

zhanyd的博客 1562

socket套接字编程

由第二部分的流程图可以总结常用的基本套接字编程函数依次为:3.1 socket()函数不论是客户端还是服务器端都必须首先调用socket函数,生成一个TCP套接字。

2401_84888945的博客 1160

socket套接字是什么

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34270865的博客 1812

什么是套接字(Socket)

应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要 通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字 (Socket)的接口,区分不同应用程序进程间的网络通信和连接。 生成套接字,主要有3个参数:通信的目的IP地址、使用的传输 ...

luzhensmart的专栏 9万+

Linux下套接字详解(二)----套接字Socket

在前面我们讲了TCP/IP、TCP和UDP的一些基本知识,但是协议只有一套,而我们系统多个TCP连接或多个应用程序进程必须通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口。套接口可以说是网络编程中一个非常重要的概念,linux以文件的形式实现套接口,与套接口相应的文件属于sockfs特殊文件

OSKernelLAB(gatieme) 2万+
上一篇: Winsock开发网络通信程序的经典入门
下一篇: 简单的TCP服务器
发现心流
博客等级 码龄20年 52粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值