主頁 > 軟體工程 > WinSock的同步異步、阻塞非阻塞問題

WinSock的同步異步、阻塞非阻塞問題

2020-09-21 11:57:27 軟體工程

用了別人寫得程式,但是沒搞懂。。。
用的select模型,是不是就是同步的方式,那阻塞和非阻塞有是怎么判斷的呢

Init里面就是連接和接收資料

TcpInit()
{
if (!m_bClientConnected)
{
int m_nPortRemote = 5025;
CString m_strRemoteIP = _T("192.168.1.58");
DWORD IP = inet_addr((LPCTSTR)m_strRemoteIP);
if(!m_pSockClient->Connect(m_strRemoteIP,m_nPortRemote))
{
int a=0;
return;
}
if(!m_pSockClient->StartReceiving(TcpStatusChangeCallBack,TcpRecvCallBack,(DWORD)this))
{
int a=0;
m_pSockClient->Close();
return;
}
m_bClientConnected=TRUE;
}
WriteCmd("FORMat:DATA INT,16\n",20);
}

接收資料里面開啟了一個執行緒,并且有兩個回呼函式,一個狀態一個資料

StartReceiving(LPStatusProc proc1,LPDataArriveProc proc2,DWORD userdata)
{
if(!m_bAvailable)
{
return FALSE;
}
if(m_nType==TCP_SOCKET_SERVER)
{
return FALSE;
}
if(!m_bCreated)
{
return FALSE;
}
if(m_bAuto)
{
return FALSE;
}

//開始自動接收
m_lpClientStatusProc=proc1;
m_lpClientDataArriveProc=proc2;
m_dwUserData=https://bbs.csdn.net/topics/userdata;
m_bAuto=TRUE;

DWORD dwThreadId;

m_hServerThread=CreateThread(NULL,0,ClientThread,this,0,&dwThreadId);

if(m_hServerThread==NULL)
{
m_bAuto=FALSE;
error=WSAGetLastError();
return FALSE;
}

return TRUE;
}

客戶端執行緒
ClientThread(LPVOID lpParameter)
{
CTCPSocket* m_pTCP=(CTCPSocket*)lpParameter;

int nRet;
char buf[256];

timeval tv={0,5000};
fd_set fs;

//不斷接收服務器發來資料
while(m_pTCP->m_bAuto)
{
FD_ZERO(&fs);
FD_SET(m_pTCP->m_sSocket,&fs);
if(select(1,&fs,NULL,NULL,&tv)==1)
{
nRet=recv(m_pTCP->m_sSocket,buf,256,0);

if(nRet==SOCKET_ERROR)
{
//出錯斷開(例如服務器關閉)
m_pTCP->error=WSAGetLastError();
closesocket(m_pTCP->m_sSocket);
m_pTCP->m_bAuto=FALSE;
TRACE("客戶端出錯斷開! \n");

//回呼處理
if(m_pTCP->m_lpClientStatusProc!=NULL)
{
char* inf;
inf=new char[22];
inf[0]='C';
inf[1]='D';
m_pTCP->m_lpClientStatusProc(inf,22,m_pTCP->m_dwUserData);
delete inf;
}

break;
}

if(nRet>0)
{
//收到新的資料
//TRACE("客戶端收到資料%d位元組! \n",nRet);

//資料回呼處理
if(m_pTCP->m_lpClientDataArriveProc!=NULL)
{
char* inf;
inf=new char[nRet];
memcpy(inf,buf,nRet);
m_pTCP->m_lpClientDataArriveProc(inf,nRet,m_pTCP->m_dwUserData);
delete inf;
}

continue;
}

if(nRet==0)
{
//服務器正常斷開
TRACE("客戶端正常斷開! \n");

//回呼處理
if(m_pTCP->m_lpClientStatusProc!=NULL)
{
char* inf;
inf=new char[22];
inf[0]='C';
inf[1]='D';
m_pTCP->m_lpClientStatusProc(inf,22,m_pTCP->m_dwUserData);
delete inf;
}
closesocket(m_pTCP->m_sSocket);
m_pTCP->m_bAuto=FALSE;

break;
}
}
}

return 0;
}

uj5u.com熱心網友回復:

感覺是同步阻塞的方式?能不能改成非阻塞呢

uj5u.com熱心網友回復:

僅供參考:
MSDN98_1\SAMPLES\VC98\SDK\NETDS\WINSOCK\SIMPLE\SIMPLEC.C
/******************************************************************************\
* simplec.c - Simple TCP/UDP client using Winsock 1.1
*
*       This is a part of the Microsoft Source Code Samples.
*       Copyright 1996-1997 Microsoft Corporation.
*       All rights reserved.
*       This source code is only intended as a supplement to
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the
*       Microsoft samples programs.
\******************************************************************************/

#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define DEFAULT_PORT 5001
#define DEFAULT_PROTO SOCK_STREAM // TCP

void Usage(char *progname) {
fprintf(stderr,"Usage\n%s -p [protocol] -n [server] -e [endpoint] \
-l [iterations]\n",
progname);
fprintf(stderr,"Where:\n\tprotocol is one of TCP or UDP\n");
fprintf(stderr,"\tserver is the IP address or name of server\n");
fprintf(stderr,"\tendpoint is the port to listen on\n");
fprintf(stderr,"\titerations is the number of loops to execute\n");
fprintf(stderr,"\t(-l by itself makes client run in an infinite loop,");
fprintf(stderr," Hit Ctrl-C to terminate it)\n");
fprintf(stderr,"Defaults are TCP , localhost and 5001\n");
WSACleanup();
exit(1);
}
int main(int argc, char **argv) {

char Buffer[128];
char *server_name= "localhost";
unsigned short port = DEFAULT_PORT;
int retval, loopflag=0;
int i, loopcount,maxloop=-1;
unsigned int addr;
int socket_type = DEFAULT_PROTO;
struct sockaddr_in server;
struct hostent *hp;
WSADATA wsaData;
SOCKET conn_socket;

if (argc >1) {
for(i=1;i <argc;i++) {
if ( (argv[i][0] == '-') || (argv[i][0] == '/') ) {
switch(tolower(argv[i][1])) {
case 'p':
if (!stricmp(argv[i+1], "TCP") )
socket_type = SOCK_STREAM;
else if (!stricmp(argv[i+1], "UDP") )
socket_type = SOCK_DGRAM;
else
Usage(argv[0]);
i++;
break;

case 'n':
server_name = argv[++i];
break;
case 'e':
port = atoi(argv[++i]);
break;
case 'l':
loopflag =1;
if (argv[i+1]) {
if (argv[i+1][0] != '-')
maxloop = atoi(argv[i+1]);
}
else
maxloop = -1;
i++;
break;
default:
Usage(argv[0]);
break;
}
}
else
Usage(argv[0]);
}
}
 
if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
fprintf(stderr,"WSAStartup failed with error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
 
if (port == 0){
Usage(argv[0]);
}

//
// Attempt to detect if we should call gethostbyname() or
// gethostbyaddr()

if (isalpha(server_name[0])) {  /* server address is a name */
hp = gethostbyname(server_name);
}
else  { /* Convert nnn.nnn address to a usable one */
addr = inet_addr(server_name);
hp = gethostbyaddr((char *)&addr,4,AF_INET);
}
if (hp == NULL ) {
fprintf(stderr,"Client: Cannot resolve address [%s]: Error %d\n",
server_name,WSAGetLastError());
WSACleanup();
exit(1);
}

//
// Copy the resolved information into the sockaddr_in structure
//
memset(&server,0,sizeof(server));
memcpy(&(server.sin_addr),hp->h_addr,hp->h_length);
server.sin_family = hp->h_addrtype;
server.sin_port = htons(port);

conn_socket = socket(AF_INET,socket_type,0); /* Open a socket */
if (conn_socket <0 ) {
fprintf(stderr,"Client: Error Opening socket: Error %d\n",
WSAGetLastError());
WSACleanup();
return -1;
}

//
// Notice that nothing in this code is specific to whether we
// are using UDP or TCP.
// We achieve this by using a simple trick.
//   When connect() is called on a datagram socket, it does not
//   actually establish the connection as a stream (TCP) socket
//   would. Instead, TCP/IP establishes the remote half of the
//   ( LocalIPAddress, LocalPort, RemoteIP, RemotePort) mapping.
//   This enables us to use send() and recv() on datagram sockets,
//   instead of recvfrom() and sendto()


printf("Client connecting to: %s\n",hp->h_name);
if (connect(conn_socket,(struct sockaddr*)&server,sizeof(server))
== SOCKET_ERROR) {
fprintf(stderr,"connect() failed: %d\n",WSAGetLastError());
WSACleanup();
return -1;
}

// cook up a string to send
//
loopcount =0;
while(1) {
wsprintf(Buffer,"This is a small test message [number %d]",loopcount++);
retval = send(conn_socket,Buffer,sizeof(Buffer),0);
if (retval == SOCKET_ERROR) {
fprintf(stderr,"send() failed: error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
printf("Sent Data [%s]\n",Buffer);
retval = recv(conn_socket,Buffer,sizeof (Buffer),0 );
if (retval == SOCKET_ERROR) {
fprintf(stderr,"recv() failed: error %d\n",WSAGetLastError());
closesocket(conn_socket);
WSACleanup();
return -1;
}
//
// We are not likely to see this with UDP, since there is no
// 'connection' established.
//
if (retval == 0) {
printf("Server closed connection\n");
closesocket(conn_socket);
WSACleanup();
return -1;
}
printf("Received %d bytes, data [%s] from server\n",retval,Buffer);
if (!loopflag){
printf("Terminating connection\n");
break;
}
else {
if ( (loopcount >= maxloop) && (maxloop >0) )
break;
}
}
closesocket(conn_socket);
WSACleanup();
}

uj5u.com熱心網友回復:

MSDN98_1\SAMPLES\VC98\SDK\NETDS\WINSOCK\SIMPLE\SIMPLES.C
/******************************************************************************\
* simples.c - Simple TCP/UDP server using Winsock 1.1
*       This is a part of the Microsoft Source Code Samples.
*       Copyright 1996-1997 Microsoft Corporation.
*       All rights reserved.
*       This source code is only intended as a supplement to
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the
*       Microsoft samples programs.
\******************************************************************************/

#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define DEFAULT_PORT 5001
#define DEFAULT_PROTO SOCK_STREAM // TCP

void Usage(char *progname) {
fprintf(stderr,"Usage\n%s -p [protocol] -e [endpoint] -i [interface]\n",
progname);
fprintf(stderr,"Where:\n\tprotocol is one of TCP or UDP\n");
fprintf(stderr,"\tendpoint is the port to listen on\n");
fprintf(stderr,"\tinterface is the ipaddr (in dotted decimal notation)");
fprintf(stderr," to bind to\n");
fprintf(stderr,"Defaults are TCP,5001 and INADDR_ANY\n");
WSACleanup();
exit(1);
}
int main(int argc, char **argv) {

char Buffer[128];
char *interface= NULL;
unsigned short port=DEFAULT_PORT;
int retval;
int fromlen;
int i;
int socket_type = DEFAULT_PROTO;
struct sockaddr_in local, from;
WSADATA wsaData;
SOCKET listen_socket, msgsock;

/* Parse arguments */
if (argc >1) {
for(i=1;i <argc;i++) {
if ( (argv[i][0] == '-') || (argv[i][0] == '/') ) {
switch(tolower(argv[i][1])) {
case 'p':
if (!stricmp(argv[i+1], "TCP") )
socket_type = SOCK_STREAM;
else if (!stricmp(argv[i+1], "UDP") )
socket_type = SOCK_DGRAM;
else
Usage(argv[0]);
i++;
break;

case 'i':
interface = argv[++i];
break;
case 'e':
port = atoi(argv[++i]);
break;
default:
Usage(argv[0]);
break;
}
}
else
Usage(argv[0]);
}
}

if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
fprintf(stderr,"WSAStartup failed with error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}

if (port == 0){
Usage(argv[0]);
}

local.sin_family = AF_INET;
local.sin_addr.s_addr = (!interface)?INADDR_ANY:inet_addr(interface);

/*
 * Port MUST be in Network Byte Order
 */
local.sin_port = htons(port);

listen_socket = socket(AF_INET, socket_type,0); // TCP socket

if (listen_socket == INVALID_SOCKET){
fprintf(stderr,"socket() failed with error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
//
// bind() associates a local address and port combination with the
// socket just created. This is most useful when the application is a
// server that has a well-known port that clients know about in advance.
//

if (bind(listen_socket,(struct sockaddr*)&local,sizeof(local) )
== SOCKET_ERROR) {
fprintf(stderr,"bind() failed with error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}

//
// So far, everything we did was applicable to TCP as well as UDP.
// However, there are certain steps that do not work when the server is
// using UDP.
//

// We cannot listen() on a UDP socket.

if (socket_type != SOCK_DGRAM) {
if (listen(listen_socket,5) == SOCKET_ERROR) {
fprintf(stderr,"listen() failed with error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
}
printf("%s: 'Listening' on port %d, protocol %s\n",argv[0],port,
(socket_type == SOCK_STREAM)?"TCP":"UDP");
while(1) {
fromlen =sizeof(from);
//
// accept() doesn't make sense on UDP, since we do not listen()
//
if (socket_type != SOCK_DGRAM) {
msgsock = accept(listen_socket,(struct sockaddr*)&from, &fromlen);
if (msgsock == INVALID_SOCKET) {
fprintf(stderr,"accept() error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
printf("accepted connection from %s, port %d\n",
inet_ntoa(from.sin_addr),
htons(from.sin_port)) ;

}
else
msgsock = listen_socket;

//
// In the case of SOCK_STREAM, the server can do recv() and
// send() on the accepted socket and then close it.

// However, for SOCK_DGRAM (UDP), the server will do
// recvfrom() and sendto()  in a loop.

if (socket_type != SOCK_DGRAM)
retval = recv(msgsock,Buffer,sizeof (Buffer),0 );
else {
retval = recvfrom(msgsock,Buffer,sizeof (Buffer),0,
(struct sockaddr *)&from,&fromlen);
printf("Received datagram from %s\n",inet_ntoa(from.sin_addr));
}

if (retval == SOCKET_ERROR) {
fprintf(stderr,"recv() failed: error %d\n",WSAGetLastError());
closesocket(msgsock);
continue;
}
if (retval == 0) {
printf("Client closed connection\n");
closesocket(msgsock);
continue;
}
printf("Received %d bytes, data [%s] from client\n",retval,Buffer);

printf("Echoing same data back to client\n");
if (socket_type != SOCK_DGRAM)
retval = send(msgsock,Buffer,sizeof(Buffer),0);
else
retval = sendto(msgsock,Buffer,sizeof (Buffer),0,
(struct sockaddr *)&from,fromlen);
if (retval == SOCKET_ERROR) {
fprintf(stderr,"send() failed: error %d\n",WSAGetLastError());
}
if (socket_type != SOCK_DGRAM){
printf("Terminating connection\n");
closesocket(msgsock);
}
else
printf("UDP server looping back for more requests\n");
continue;
}
}

uj5u.com熱心網友回復:

MSDN98_1\SAMPLES\VC98\SDK\NETDS\WINSOCK\SIMPLE\IOCTL.C
/******************************************************************************\
* ioctl.c - TCP server
*
*       This is a part of the Microsoft Source Code Samples.
*       Copyright 1996-1997 Microsoft Corporation.
*       All rights reserved.
*       This source code is only intended as a supplement to
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the
*       Microsoft samples programs.
\******************************************************************************/



#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define DEFAULT_PORT 5001

int ReadAndEcho(SOCKET , char *,int ) ;
int WriteMessage(SOCKET , char *,int ) ;

void Usage(char *progname) {
fprintf(stderr,"Usage\n%s -e [endpoint] -i [interface]\n",
progname);
fprintf(stderr,"Where:\n");
fprintf(stderr,"\tendpoint is the port to listen on\n");
fprintf(stderr,"\tinterface is the ipaddr (in dotted decimal notation)");
fprintf(stderr," to bind to\n");
fprintf(stderr,"Defaults are 5001 and INADDR_ANY\n");
WSACleanup();
exit(1);
}
int main(int argc, char **argv) {

char Buffer[128];
char *interface= NULL;
unsigned short port=DEFAULT_PORT;
int fromlen;
int i, ioctl_opt =1;
struct sockaddr_in local, from;
WSADATA wsaData;
SOCKET listen_socket, msgsock;
fd_set readfds, writefds, exceptfds;

/* Parse arguments */
if (argc >1) {
for(i=1;i <argc;i++) {
if ( (argv[i][0] == '-') || (argv[i][0] == '/') ) {
switch(tolower(argv[i][1])) {
case 'i':
interface = argv[++i];
break;
case 'e':
port = atoi(argv[++i]);
break;
default:
Usage(argv[0]);
break;
}
}
else
Usage(argv[0]);
}
}
 
if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) {
fprintf(stderr,"WSAStartup failed with error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
 
if (port == 0){
Usage(argv[0]);
}

//
// The fd sets should be zeroed out before using them to prevent errors.
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
memset(Buffer,0,sizeof(Buffer));

local.sin_family = AF_INET;

//
// bind to specific interface if desired.

local.sin_addr.s_addr = (!interface)?INADDR_ANY:inet_addr(interface);

/*
 * Port MUST be in Network Byte Order
 */
local.sin_port = htons(port);

listen_socket = socket(AF_INET, SOCK_STREAM,0); // TCP socket
if (listen_socket == INVALID_SOCKET){
fprintf(stderr,"socket() failed with error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
//
// bind() associates a local address and port combination with the
// socket just created.

if (bind(listen_socket,(struct sockaddr*)&local,sizeof(local) )
== SOCKET_ERROR) {
fprintf(stderr,"bind() failed with error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}

//
// start listening on the socket for incoming connections
//
if (listen(listen_socket,5) == SOCKET_ERROR) {
fprintf(stderr,"listen() failed with error %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
printf("%s: Listening on port %d\n",argv[0],port);

//
// Set the socket to non-blocking mode.
//
if (ioctlsocket(listen_socket,FIONBIO,&ioctl_opt) == SOCKET_ERROR) {
fprintf(stderr,"ioctlsocket failed %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
//
// The structure of the loop below is very simple. We only accept one
// connection at a time. As soon as another client connects, we
// disconnect the first one, and start talking to the new client.
// All this server does is to echo the data received on the socket
// back to the client.
//
// This is not a very realistic server, but it does serve to show that
// select() does not scale very well on win32. If we were dealing
// with more than one client, we would have to have a list of sockets
// that are in each fdset to be able to check them when select()
// returns.
//
while(1) {

//
// A socket in the listen() state becomes ready to read when a
// client connects to it. An accept() will complete without
// blocking.
// Since select sets the sockets that are ready to be read from or
// written to, we have to include listen_socket in the fdset each time
// through the loop.
//

FD_SET(listen_socket,&readfds);

i = select(0,&readfds,&writefds,&exceptfds,NULL);
if (i == SOCKET_ERROR) {
fprintf(stderr,"select failed %d\n",WSAGetLastError());
}
if (i==0){
fprintf(stderr,"Select returned no fds ready\n");
}

if (FD_ISSET(listen_socket, &readfds)){
//
// close the previous client socket.
// We must also clear it from the fdset to prevent select()
// from failing.
//
closesocket(msgsock);
FD_CLR(msgsock,&readfds);
FD_CLR(msgsock,&writefds);
fromlen = sizeof(from);
msgsock= accept(listen_socket,(struct sockaddr*)&from,&fromlen);
if (msgsock == INVALID_SOCKET) {
fprintf(stderr,"accept failed %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
FD_SET(msgsock,&writefds);
FD_SET(msgsock,&readfds);
continue;
}
if (FD_ISSET(msgsock,&readfds) ) {
//
// socket is ready to read, i.e., there is data on the socket.
//
if (ReadAndEcho(msgsock,Buffer,sizeof(Buffer))<0) {
fprintf(stderr,"terminating connection\n");
FD_CLR(msgsock,&readfds);
FD_CLR(msgsock,&writefds);
closesocket(msgsock);
continue;
}
}
if (FD_ISSET(msgsock,&writefds) ){
if (WriteMessage(msgsock,Buffer,sizeof(Buffer)) <=0) {
fprintf(stderr,"terminating connection\n");
FD_CLR(msgsock,&readfds);
FD_CLR(msgsock,&writefds);
closesocket(msgsock);
continue;
}
}
FD_SET(msgsock,&writefds);
FD_SET(msgsock,&readfds);
}
}
int ReadAndEcho(SOCKET insock, char *Buffer,int size) {
int rc;

rc = recv(insock,Buffer,size,0);

if (rc == SOCKET_ERROR) {
fprintf(stderr,"recv() failed with error %d\n",WSAGetLastError());
return -1;
}
if (rc ==0) {
fprintf(stderr,"Connection closed by client\n");
return 0;
}
printf("Received [%s] from client\n",Buffer);
return rc;
}
int WriteMessage(SOCKET outsock, char *Buffer,int size) {
int rc;
int lasterr;

printf("Sending [%s] to client\n",Buffer);
rc = send(outsock,Buffer,size, 0);

if (rc == SOCKET_ERROR) {
  lasterr = WSAGetLastError();
  if (lasterr == WSAEWOULDBLOCK)
return 0;
  else {
fprintf(stderr,"send() failed with error %d\n",lasterr);
return -1;
  }
}
if (rc ==0) {
fprintf(stderr,"Connection closed by client\n");
}
return rc;
}

uj5u.com熱心網友回復:

同步是阻塞的,異步是非阻塞的,所謂阻塞,就是你發送資料,然后等待回傳資料,資料沒有回傳,就死等,直到資料回傳或者超時;

非阻塞是你發出一個接收命令,命令發出后不管資料有沒有收到,就執行代碼的后面的指令,而當資料回傳后,系統發出事件通知你處理接收到的資料,這種模式是非阻塞,是異步的

uj5u.com熱心網友回復:

是否阻塞, 是看socket有沒有設定非阻塞模式, 默認創建的socket都是阻塞模式, 
需要呼叫api  ioctlsocket設定非阻塞模式.

select一般都是為了把非阻塞模式的, 變成阻塞模式.  為何這么做, 為什么不直接使用阻塞模式呢?

因為select可以同時判斷多個socket連接中是否有資料可以接收,  阻塞模式做不到.
并且同時也能做到沒有資料的時候,阻塞等待有資料才做事情, 不會浪費CPU.  有阻塞模式的相同的好處.
再并且, 還可方便的設定接收超時.  跟阻塞模式一樣.

uj5u.com熱心網友回復:

參考 6 樓 xiaohuh421 的回復:
是否阻塞, 是看socket有沒有設定非阻塞模式, 默認創建的socket都是阻塞模式, 
需要呼叫api  ioctlsocket設定非阻塞模式.

select一般都是為了把非阻塞模式的, 變成阻塞模式.  為何這么做, 為什么不直接使用阻塞模式呢?

因為select可以同時判斷多個socket連接中是否有資料可以接收,  阻塞模式做不到.
并且同時也能做到沒有資料的時候,阻塞等待有資料才做事情, 不會浪費CPU.  有阻塞模式的相同的好處.
再并且, 還可方便的設定接收超時.  跟阻塞模式一樣.

恩,那上面那個程式應該就是同步阻塞的?

uj5u.com熱心網友回復:

什么叫異步阻塞.......

沒有這種說法.

uj5u.com熱心網友回復:

用事實說話,焦點訪談;
用代碼說話,真程式員。

uj5u.com熱心網友回復:

http://bbs.csdn.net/topics/390374955

轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/96806.html

標籤:界面

上一篇:【胡亂提問】能否實作C++作為后臺邏輯實作,前臺界面通過JS實作-。-

下一篇:error C2065: 'GetDIgltem' : undeclared identifier

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • Git本地庫既關聯GitHub又關聯Gitee

    創建代碼倉庫 使用gitee舉例(github和gitee差不多) 1.在gitee右上角點擊+,選擇新建倉庫 ? 2.選擇填寫倉庫資訊,然后進行創建 ? 3.服務端已經準備好了,本地開始作準備 (1)Git 全域設定 git config --global user.name "成鈺" git c ......

    uj5u.com 2020-09-10 05:04:14 more
  • CODING DevOps 代碼質量實戰系列第二課,相約周三

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。**《DevOps 代碼質量實戰(PHP 版)》**為 CODING DevOps 代碼質量實戰系列的第二課,同時也是本系列的 PHP ......

    uj5u.com 2020-09-10 05:07:43 more
  • 推薦Scrum書籍

    推薦Scrum書籍 直接上干貨,推薦書籍清單如下(推薦有順序的哦) Scrum指南 Scrum精髓 Scrum敏捷軟體開發 Scrum捷徑 硝煙中的Scrum和XP : 我們如何實施Scrum 敏捷軟體開發:Scrum實戰指南 Scrum要素 大規模Scrum:大規模敏捷組織的設計 用戶故事地圖 用 ......

    uj5u.com 2020-09-10 05:07:45 more
  • CODING DevOps 代碼質量實戰系列最后一課,周四發車

    隨著 ToB(企業服務)的興起和 ToC(消費互聯網)產品進入成熟期,線上故障帶來的損失越來越大,代碼質量越來越重要,而「質量內建」正是 DevOps 核心理念之一。 **《DevOps 代碼質量實戰(Java 版)》**為 CODING DevOps 代碼質量實戰系列的最后一課,同時也是本系列的 ......

    uj5u.com 2020-09-10 05:07:52 more
  • 敏捷軟體工程實踐書籍

    Scrum轉型想要做好,第一步先了解并真正落實Scrum,那么我推薦的Scrum書籍是要看懂并實踐的。第二步是團隊的工程實踐要做扎實。 下面推薦工程實踐書單: 重構:改善既有代碼的設計 決議極限編程 : 擁抱變化 代碼整潔代碼 程式員的職業素養 修改代碼的藝術 撰寫可讀代碼的藝術 測驗驅動開發 : ......

    uj5u.com 2020-09-10 05:07:55 more
  • Jenkins+svn+nginx實作windows環境自動部署vue前端專案

    前面文章介紹了Jenkins+svn+tomcat實作自動化部署,現在終于有空抽時間出來寫下Jenkins+svn+nginx實作自動部署vue前端專案。 jenkins的安裝和配置已經在前面文章進行介紹,下面介紹實作vue前端專案需要進行的哪些額外的步驟。 注意:在安裝jenkins和nginx的 ......

    uj5u.com 2020-09-10 05:08:49 more
  • CODING DevOps 微服務專案實戰系列第一課,明天等你

    CODING DevOps 微服務專案實戰系列第一課**《DevOps 微服務專案實戰:DevOps 初體驗》**將由 CODING DevOps 開發工程師 王寬老師 向大家介紹 DevOps 的基本理念,并探討為什么現代開發活動需要 DevOps,同時將以 eShopOnContainers 項 ......

    uj5u.com 2020-09-10 05:09:14 more
  • CODING DevOps 微服務專案實戰系列第二課來啦!

    近年來,工程專案的結構越來越復雜,需要接入合適的持續集成流水線形式,才能滿足更多變的需求,那么如何優雅地使用 CI 能力提升生產效率呢?CODING DevOps 微服務專案實戰系列第二課 《DevOps 微服務專案實戰:CI 進階用法》 將由 CODING DevOps 全堆疊工程師 何晨哲老師 向 ......

    uj5u.com 2020-09-10 05:09:33 more
  • CODING DevOps 微服務專案實戰系列最后一課,周四開講!

    隨著軟體工程越來越復雜化,如何在 Kubernetes 集群進行灰度發布成為了生產部署的”必修課“,而如何實作安全可控、自動化的灰度發布也成為了持續部署重點關注的問題。CODING DevOps 微服務專案實戰系列最后一課:**《DevOps 微服務專案實戰:基于 Nginx-ingress 的自動 ......

    uj5u.com 2020-09-10 05:10:00 more
  • CODING 儀表盤功能正式推出,實作作業資料可視化!

    CODING 儀表盤功能現已正式推出!該功能旨在用一張張統計卡片的形式,統計并展示使用 CODING 中所產生的資料。這意味著無需額外的設定,就可以收集歸納寶貴的作業資料并予之量化分析。這些海量的資料皆會以圖表或串列的方式躍然紙上,方便團隊成員隨時查看各專案的進度、狀態和指標,云端協作迎來真正意義上 ......

    uj5u.com 2020-09-10 05:11:01 more
最新发布
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:41:12 more
  • windows系統git使用ssh方式和gitee/github進行同步

    使用git來clone專案有兩種方式:HTTPS和SSH:
    HTTPS:不管是誰,拿到url隨便clone,但是在push的時候需要驗證用戶名和密碼;
    SSH:clone的專案你必須是擁有者或者管理員,而且需要在clone前添加SSH Key。SSH 在push的時候,是不需要輸入用戶名的,如果配置... ......

    uj5u.com 2023-04-19 08:35:34 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:05:44 more
  • 2023年農牧行業6大CRM系統、5大場景盤點

    在物聯網、大資料、云計算、人工智能、自動化技術等現代資訊技術蓬勃發展與逐步成熟的背景下,數字化正成為農牧行業供給側結構性變革與高質量發展的核心驅動因素。因此,改造和提升傳統農牧業、開拓創新現代智慧農牧業,加快推進農牧業的現代化、資訊化、數字化建設已成為農牧業發展的重要方向。 當下,企業數字化轉型已經 ......

    uj5u.com 2023-04-18 08:00:18 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:20:31 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:55 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:18:51 more
  • 談一談我對協同開發的一些認識

    如今各互聯網公司普通都使用敏捷開發,采用小步快跑的形式來進行專案開發。如果是小專案或者小需求,那一個開發可能就搞定了。但對于電商等復雜的系統,其功能多,結構復雜,一個人肯定是搞不定的,所以都是很多人來共同開發維護。以我曾經待過的商城團隊為例,光是后端開發就有七十多人。 為了更好地開發這類大型系統,往 ......

    uj5u.com 2023-04-17 08:18:00 more
  • 專案管理PRINCE2核心知識點整理

    PRINCE2,即 PRoject IN Controlled Environment(受控環境中的專案)是一種結構化的專案管理方法論,由英國政府內閣商務部(OGC)推出,是英國專案管理標準。
    PRINCE2 作為一種開放的方法論,是一套結構化的專案管理流程,描述了如何以一種邏輯性的、有組織的方法,... ......

    uj5u.com 2023-04-17 08:17:55 more
  • 計算機組成原理—存盤器

    計算機組成原理—硬體結構 二、存盤器 1.概述 存盤器是計算機系統中的記憶設備,用來存放程式和資料 1.1存盤器的層次結構 快取-主存層次主要解決CPU和主存速度不匹配的問題,速度接近快取 主存-輔存層次主要解決存盤系統的容量問題,容量接近與價位接近于主存 2.主存盤器 2.1概述 主存與CPU的聯 ......

    uj5u.com 2023-04-17 08:12:06 more