非阻塞套接字和epoll
要求:
1、從配置檔案中讀取資料;
2、編寫可滾動的日誌檔案;
3、實現非阻塞套接字,應用epoll;
4、實現心跳檢測(心跳包);
5、分執行緒處理
client.c 客戶機程式
#include "head.h" #include "config.h" #include "heart_client.h" #define BUFFER_SIZE 40 int main(int argc, char *argv[]) { int client_sockfd; int len; struct sockaddr_in remote_addr; // 伺服器端網路地址結構體 memset(&remote_addr,0,sizeof(remote_addr)); // 資料初始化--清零 remote_addr.sin_family=AF_INET; // 設定為IP通訊 char s_ip[20]; GetConfigFileStringValue("IPANDPORT", "IP", "127.0.0.1", s_ip, sizeof(s_ip), "Config.ini"); printf("IP : %s\n", s_ip); remote_addr.sin_addr.s_addr=inet_addr(s_ip);// 伺服器IP地址 uint16_t port = GetConfigFileIntValue("IPANDPORT", "PORT", 8866, "Config.ini"); printf("port : %d\n", (int)port); if (port == -1){ // 判斷獲取到的年齡是否正確 printf("Get port failed!\n"); return -1; } remote_addr.sin_port=htons(port); // 伺服器埠號 // 建立客戶端套接字--IPv4協議,面向連線通訊,TCP協議 client_sockfd=socket(AF_INET,SOCK_STREAM,0); if(client_sockfd<0){ perror("client socket creation failed"); exit(EXIT_FAILURE); } // 將套接字繫結到伺服器的網路地址上 if((connect(client_sockfd,(struct sockaddr *)&remote_addr,sizeof(struct sockaddr)))<0){ perror("connect to server failed"); exit(EXIT_FAILURE); } pthread_t pth; int err; int *client_sockfd_1 = (int *)malloc(sizeof(int)); *client_sockfd_1 = client_sockfd; if((err = pthread_create(&pth, NULL, send_heart, (void *)client_sockfd_1)) != 0){ fprintf(stderr, "pthread_create: %s\n", strerror(err)); exit(1); } sleep(5); // 迴圈監聽伺服器請求 pd = (DATA_PACK *)malloc(sizeof(DATA_PACK)); char *buf = (char *)malloc(sizeof(*pd)); pd->data_type=8; strcpy(pd->name, "127.0.0.1"); pd->num1= (int )GetConfigFileIntValue("TWONUMBER", "NUMBER1", 0x3f3f3f3f, "Config.ini"); pd->num2 = (int )GetConfigFileIntValue("TWONUMBER", "NUMBER2", 0x3f3f3f3f, "Config.ini"); printf("兩個數為:%d %d\n",pd->num1,pd->num2); len = sizeof(*pd); memcpy(buf, pd, len); send(client_sockfd,buf,len,0); // 接收伺服器端資訊 len=recv(client_sockfd,pd,BUFFER_SIZE,0); if(pd->data_type==8) printf("receive from server %s: %d\n",pd->name,pd->num1); else printf("receive from server %s: 傳送數字個數不正確\n",pd->name); if(len<0) { perror("receive from server failed"); exit(EXIT_FAILURE); } free(pd); close(client_sockfd);// 關閉套接字 return 0; }
config.c //實現獲取配置檔案中的內容
#include "config.h" // 功能描述: 獲取配置檔案完整路徑(包含檔名) // 輸入引數: pszConfigFileName-配置檔名 // pszWholePath-配置檔案完整路徑(包含檔名) void GetCompletePath(UINT8 *pszConfigFileName, UINT8 *pszWholePath){ UINT8 *pszHomePath = NULL; UINT8 szWholePath[256] = {0}; // 先對輸入引數進行異常判斷 if (pszConfigFileName == NULL || pszWholePath == NULL){ printf("GetCompletePath: input parameter(s) is NULL!\n"); return; } pszHomePath = (UINT8 *)getenv("HOME"); // 獲取當前使用者所在的路徑 if (pszHomePath == NULL){ printf("GetCompletePath: Can't find home path!\n"); return; } // 拼裝配置檔案路徑 snprintf(szWholePath, sizeof(szWholePath)-1, "%s", pszConfigFileName); strncpy(pszWholePath, szWholePath, strlen(szWholePath)); } // 功能描述: 獲取具體的字串值 // 輸入引數: fp-配置檔案指標 // pszSectionName-段名, 如: GENERAL // pszKeyName-配置項名, 如: EmployeeName // iOutputLen-輸出快取長度 // 輸出引數: pszOutput-輸出快取 void GetStringContentValue(FILE *fp, UINT8 *pszSectionName, UINT8 *pszKeyName, UINT8 *pszOutput, UINT32 iOutputLen){ UINT8 szSectionName[100] = {0}; UINT8 szKeyName[100] = {0}; UINT8 szContentLine[256] = {0}; UINT8 szContentLineBak[256] = {0}; UINT32 iContentLineLen = 0; UINT32 iPositionFlag = 0; // 先對輸入引數進行異常判斷 if (fp == NULL || pszSectionName == NULL || pszKeyName == NULL || pszOutput == NULL){ printf("GetStringContentValue: input parameter(s) is NULL!\n"); return; } sprintf(szSectionName, "[%s]", pszSectionName); strcpy(szKeyName, pszKeyName); while (feof(fp) == 0){ memset(szContentLine, 0x00, sizeof(szContentLine)); fgets(szContentLine, sizeof(szContentLine), fp); // 獲取段名 // 判斷是否是註釋行(以;開頭的行就是註釋行)或以其他特殊字元開頭的行 if (szContentLine[0] == ';' || szContentLine[0] == '\r' || szContentLine[0] == '\n' || szContentLine[0] == '\0'){ continue; } // 匹配段名 if (strncasecmp(szSectionName, szContentLine, strlen(szSectionName)) == 0) { while (feof(fp) == 0){ memset(szContentLine, 0x00, sizeof(szContentLine)); memset(szContentLineBak, 0x00, sizeof(szContentLineBak)); fgets(szContentLine, sizeof(szContentLine), fp); // 獲取欄位值 // 判斷是否是註釋行(以;開頭的行就是註釋行) if (szContentLine[0] == ';'){ continue; } memcpy(szContentLineBak, szContentLine, strlen(szContentLine)); // 匹配配置項名 if (strncasecmp(szKeyName, szContentLineBak, strlen(szKeyName)) == 0) { iContentLineLen = strlen(szContentLine); for (iPositionFlag = strlen(szKeyName); iPositionFlag <= iContentLineLen; iPositionFlag ++){ if (szContentLine[iPositionFlag] == ' '){ continue; } if (szContentLine[iPositionFlag] == '='){ break; } iPositionFlag = iContentLineLen + 1; break; } iPositionFlag = iPositionFlag + 1; // 跳過=的位置 if (iPositionFlag > iContentLineLen){ continue; } memset(szContentLine, 0x00, sizeof(szContentLine)); strcpy(szContentLine, szContentLineBak + iPositionFlag); // 去掉內容中的無關字元 for (iPositionFlag = 0; iPositionFlag < strlen(szContentLine); iPositionFlag ++){ if (szContentLine[iPositionFlag] == '\r' || szContentLine[iPositionFlag] == '\n' || szContentLine[iPositionFlag] == '\0'){ szContentLine[iPositionFlag] = '\0'; break; } } // 將配置項內容拷貝到輸出快取中 strncpy(pszOutput, szContentLine, iOutputLen-1); break; } else if (szContentLine[0] == '['){ break; } } break; } } } // 功能描述: 從配置檔案中獲取字串 // 輸入引數: pszSectionName-段名, 如: GENERAL // pszKeyName-配置項名, 如: EmployeeName // pDefaultVal-預設值 // iOutputLen-輸出快取長度 // pszConfigFileName-配置檔名 // 輸出引數: pszOutput-輸出快取 void GetConfigFileStringValue(UINT8 *pszSectionName, UINT8 *pszKeyName, UINT8 *pDefaultVal, UINT8 *pszOutput, UINT32 iOutputLen, UINT8 *pszConfigFileName){ FILE *fp = NULL; UINT8 szWholePath[256] = {0}; // 先對輸入引數進行異常判斷 if (pszSectionName == NULL || pszKeyName == NULL || pszOutput == NULL || pszConfigFileName == NULL){ printf("GetConfigFileStringValue: input parameter(s) is NULL!\n"); return; } // 獲取預設值 if (pDefaultVal == NULL){ strcpy(pszOutput, ""); } else{ strcpy(pszOutput, pDefaultVal); } // 開啟配置檔案 GetCompletePath(pszConfigFileName, szWholePath); fp = fopen(szWholePath, "r"); if (fp == NULL){ printf("GetConfigFileStringValue: open %s failed!\n", szWholePath); return; } // 呼叫函式用於獲取具體配置項的值 GetStringContentValue(fp, pszSectionName, pszKeyName, pszOutput, iOutputLen); // 關閉檔案 fclose(fp); fp = NULL; } // 功能描述: 從配置檔案中獲取整型變數 // 輸入引數: pszSectionName-段名, 如: GENERAL // pszKeyName-配置項名, 如: EmployeeName // iDefaultVal-預設值 // pszConfigFileName-配置檔名 // 輸出引數: 無 // 返 回 值: iGetValue-獲取到的整數值 -1-獲取失敗 INT32 GetConfigFileIntValue(UINT8 *pszSectionName, UINT8 *pszKeyName, UINT32 iDefaultVal, UINT8 *pszConfigFileName){ UINT8 szGetValue[512] = {0}; INT32 iGetValue = 0; // 先對輸入引數進行異常判斷 if (pszSectionName == NULL || pszKeyName == NULL || pszConfigFileName == NULL){ printf("GetConfigFileIntValue: input parameter(s) is NULL!\n"); return -1; } GetConfigFileStringValue(pszSectionName, pszKeyName, NULL, szGetValue, 512-1, pszConfigFileName); // 先將獲取的值存放在字元型快取中 if (szGetValue[0] == '\0' || szGetValue[0] == ';'){ // 如果是結束符或分號, 則使用預設值 iGetValue = iDefaultVal; } else{ iGetValue = atoi(szGetValue); } return iGetValue; }
heart_client.c //客戶client傳送心跳程式
#include "head.h" #include "heart.h" void *send_heart(void *addr){ int* client_sockfd = (int*)addr; printf("client_socket: %d\n", *client_sockfd); pd = (DATA_PACK *)malloc(sizeof(DATA_PACK)); strcpy(pd->name, "127.0.0.1"); while(1){ //write(client_sockfd,pd,sizeof(DATA_PACK)); send(*client_sockfd,pd,sizeof(*pd),0); sleep(3); //定時3秒 } free(client_sockfd); free(pd); return NULL; }
WriteSysLog.c //實現書寫日誌
#include "head.h"
#include "WriteSysLog.h"
void WriteSysLog(char *str){
char buf[512],name[20]="./syslog.log_0",s[10];
long MAXLEN = 10*1024*1024;//10MB
time_t timep;
FILE *fp = NULL;
struct tm *p;
time(&timep);
p = localtime(&timep);
memset(buf,0,sizeof(buf));
sprintf(buf,"%d-%d-%d %d:%d:%d : ",(1900+p->tm_year),(1+p->tm_mon),p->tm_mday,p->tm_hour, p->tm_min, p->tm_sec);
//星期p->tm_wday
strcat(buf,str);
strcat(buf,"\r\n");
fp = fopen(name,"r");
if(fp==NULL){
fp = fopen(name,"w+");
}
else{
fseek(fp,0,2);
if(ftell(fp) >= MAXLEN){
fclose(fp);
xx++;
int len,j,k;
len=strlen(name);
for(j=0;j<len;j++){
if(name[j]=='_')
k=j;
}
for(j=k+1;j<len;j++){
name[j]='\0';
}
sprintf(s,"%d",xx);
strcat(name,s);
memset(s,'\0',sizeof(s));
fp = fopen(name,"w+");
//大於10MB則產生新日誌檔案
}
else{
fclose(fp);
fp = fopen(name,"a");
}
}
fwrite(buf,1,strlen(buf),fp);
fflush(fp);
fsync(fileno(fp));
fclose(fp);
}
addfd.c //往epoll中新增套接字
#include "head.h"
#include "addfd.h"
void addfd(int epollfd, int fd, int flag){
struct epoll_event event;
memset(&event, 0x00, sizeof(event));
event.data.fd = fd;
event.events = EPOLLIN;
if(flag){
event.events |= EPOLLET;
}
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
setnonblocking(fd);
}
et.c //實現資料的接收和傳送
#include "head.h"
#include "et.h"
#include "heart.h"
extern s_t *s_head;
extern volatile g_stop;
#define MAX_LEN 1024
void *et(void *arg){
pth_etlt *pth_arg = (pth_etlt *)arg;
struct epoll_event* events = pth_arg->events;
int number = pth_arg->number;
int epollfd = pth_arg->epollfd;
int listenfd = pth_arg->listenfd;
int i;
DATA_PACK *data = (DATA_PACK *)malloc(sizeof(DATA_PACK));
int p = 0;
DATA_PACK *num=(DATA_PACK *)malloc(sizeof(DATA_PACK));
char *buf=(char *)malloc(sizeof(*num));
int len=sizeof(*num);
for(i = 0; i < number; i++){
int sockfd = events[i].data.fd;
struct sockaddr_in client_address;
if(sockfd == listenfd){
socklen_t client_addresslen = sizeof(client_address);
int connfd = accept(listenfd, (struct sockaddr*)&client_address, &client_addresslen);
addfd(epollfd, connfd, 1);
printf("client ip: %s port: %d\n", inet_ntoa(client_address.sin_addr),ntohs(client_address.sin_port));
s_t *p = (s_t *)malloc(sizeof(s_t)), *q;
strcpy(p->peerip, inet_ntoa(client_address.sin_addr));
strcpy(p->name, inet_ntoa(client_address.sin_addr));
p->sockfd = sockfd;
p->count = 0;
q = s_head->next;
s_head->next = p;
p->next = q;
}
else if(events[i].events & EPOLLIN){
// printf("ET once\r\n");
while(g_stop){
//memset(data, 0x00, sizeof(*data));
int ret = recv(sockfd, data, MAX_LEN, 0);
if(ret < 0){
if((errno == EAGAIN) || (errno == EWOULDBLOCK)){
//printf("read later \r\n");
break;
}
close(sockfd);
break;
}
else if(ret == 0){
close(sockfd);
}
else{
char s[128];
heart_handler(sockfd,data);
sprintf(s,"%s 收到了資料:%d %d",data->name,data->num1,data->num2);
WriteSysLog(s);
if(data->data_type==8){
if(data->num1==0x3f3f3f3f||data->num2==0x3f3f3f3f){
sprintf(s,"%s 收到的資料個數不對",data->name);
WriteSysLog(s);
num->data_type=4;
strcpy(num->name,"127.0.0.1");
send(sockfd,buf,len,0);
break;
}
memset(s,'\0',sizeof(s));
//sprintf(s,"%s 收到了資料:%d %d",data->name,data->num1,data->num2);
//WriteSysLog(s);
strcpy(num->name,"127.0.0.1");
num->data_type=8;
num->num1=data->num1 + data->num2;
memcpy(buf,num,len);
send(sockfd,buf,len,0);
memset(s,'\0',sizeof(s));
sprintf(s,"向 %s 傳送的資料為:%d",data->name,num->num1);
WriteSysLog(s);
}
}
}
}
else{
printf("做了另外的事情\r\n");
}
}
pthread_exit((void *)data);
}
heart.c //實現心跳檢測
#include "head.h"
#include "heart.h"
extern s_t *s_head;
extern volatile g_stop;
void init_shead(){
s_head = (s_t *)malloc(sizeof(s_t));
}
void heart_handler(int sockfd,DATA_PACK *pd){
s_t *cur = s_head->next;
while( NULL != cur){
if(strcmp(cur->name,pd->name) == 0){
cur->count = 0;
printf("客戶端IP: %s :使用者 %s 連線正常\n",cur->peerip,pd->name);
}
cur = cur->next;
}
}
void *heart_check(void *p)
{
printf("心跳檢測執行緒已開啟!\n");
while(g_stop){
s_t *temp = NULL;
s_t **ppNode = &s_head->next;
while(NULL != (*ppNode) && g_stop){
if((*ppNode)->count == 5){
g_stop = 0;
printf("客戶端IP: %s :使用者 %s 已經掉線!!\n",(*ppNode)->peerip,(*ppNode)->name);
close((*ppNode)->sockfd);
temp = *ppNode;
*ppNode = (*ppNode)->next;
free(temp);
temp = NULL;
return;
}
else if((*ppNode)->count > 0){
printf("客戶端IP: %s :使用者 %s 連線異常!\n",(*ppNode)->peerip,(*ppNode)->name);
(*ppNode)->count++;
printf("count = %d\n",(*ppNode)->count);
ppNode = &((*ppNode)->next);
continue;
}
else if((*ppNode)->count == 0){
(*ppNode)->count++;
printf("count = %d\n",(*ppNode)->count);
ppNode = &((*ppNode)->next);
}
else;
}
sleep(3);
}
pthread_exit((void *)1);
}
lt.c //實現監聽檢測
#include "head.h"
#include "lt.h"
void lt(struct epoll_event* events, int number, int epollfd, int listenfd){
char buf[BUF_SIZE];
int i;
for(i = 0; i < number; i++){
int sockfd = events[i].data.fd;
if(sockfd == listenfd){
struct sockaddr_in client_address;
socklen_t client_addresslen = sizeof(client_address);
int connfd = accept(listenfd, (struct sockaddr *)&client_address, &client_addresslen);
if(connfd < 0){
printf("接受失敗\r\n");
exit(1);
}
addfd(epollfd, connfd, 0);
}
else if(events[i].events & EPOLLIN){
printf("LT once\r\n");
memset(buf, 0x00, sizeof(buf));
int ret = recv(sockfd, buf, sizeof(buf)-1, 0);
if(ret <= 0){
printf("rec 0\r\n");
close(sockfd);
continue;
}
printf("recv data from %d buf is %s\r\n", sockfd, buf);
}
else{
printf("做了另外的一些事\r\n");
}
}
}
server.c //伺服器程式
#include "head.h"
#include "lt.h"
#include "et.h"
#include "addfd.h"
#include "heart.h"
s_t *s_head = NULL;
volatile g_stop=1;
int main(int argc, char **argv){
if(argc <= 2){
printf("請重新執行並在./server 後輸入ip地址(127.0.0.1)和埠號(8867)\r\n");
exit(1);
}
const char* ip = argv[1];
int port = atoi(argv[2]);
int ret = 0;
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr);
address.sin_port = htons(port);
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
assert(listenfd >= 0);
ret = bind(listenfd, (struct sockaddr *)&address, sizeof(address));
assert(ret != -1);
ret = listen(listenfd, 5);
assert(ret != -1);
struct epoll_event events[MAX_SOCKET_NUMBERS];
int epollfd = epoll_create(5);
assert(epollfd != -1);
addfd(epollfd,listenfd, 1);
int err1;
pthread_t pth1;
init_shead();
if( (err1 = pthread_create(&pth1, NULL, heart_check, (void *)0) ) != 0){
puts("--------------------");
fprintf(stderr, "pthread_creat : %s\n", strerror(err1));
exit(1);
}
DATA_PACK *num;
while(g_stop){
int ret = epoll_wait(epollfd, events, MAX_SOCKET_NUMBERS, -1);
if(ret < 0){
printf("epoll等候失敗\r\n");
exit(1);
}
int err;
pthread_t pth;
pth_etlt arg = {events, ret, epollfd, listenfd};
if( (err = pthread_create(&pth, NULL, et, (void *)&arg) ) != 0){
fprintf(stderr, "pthread_creat : %s\n", strerror(err));
exit(1);
}
pthread_join(pth, (void**)&num);
}
close(listenfd);
return 0;
}
setnonblocking.c //實現將套接字轉換為非阻塞
#include "head.h"
#include "setnonblocking.h"
int setnonblocking(int fd){
int old_option = fcntl(fd, F_GETFL);
int new_option = old_option | O_NONBLOCK;
fcntl(fd, F_SETFL, new_option);
return new_option;
}
Config.ini //配置檔案,存放資料
[IPANDPORT]
;the value of IP
IP=127.0.0.1
;the value of port
PORT=8867
[TWONUMBER]
;the value of number1
NUMBER1=1052
;the value of number2
NUMBER2=568
相關推薦
非阻塞套接字和epoll
要求: 1、從配置檔案中讀取資料; 2、編寫可滾動的日誌檔案; 3、實現非阻塞套接字,應用epoll; 4、實現心跳檢測(心跳包); 5、分執行緒處理 client.c 客戶機程式 #include "head.h" #include "config.h" #inc
11 非阻塞套接字與IO多路復用(進階)
img 一行 回調 lba let 自己 elf accept error: 1、非阻塞套接字 第一部分 基本IO模型 1.普通套接字實現的服務端的缺陷 一次只能服務一個客戶端! 2.普通套接字實現的服務端的瓶頸!!! accept阻塞! 在沒有新的套接字來之前,不能處
非阻塞套接字實現並發處理
pre ror enc con put 服務 生成 import data 服務端 import socket server = socket.socket() server.setblocking(False) server.bind((‘0.0.0.0‘,8080)
選擇模型--非阻塞套接字詳解
0x01什麼是選擇模型 普通套接字程式設計,常常會遇到阻塞主程序,比如recv,read等,如果沒有資料發過來會一直等待。有沒有辦法讓程序等待一段時間,再退出呢。這時候使用選擇模型就能解決這個問題。 原理–I/O多路複用:通過一個fd_set集合來管理套接字,當某個socket可讀或者可
非阻塞套接字connect
EINPROGRESS The socket is nonblocking and the connection cannot be completed immediately. It is possible to select(2) or pol
非阻塞套接字資料收集
1、 兩種I/O模式 * 阻塞模式: 執行I/O操作完成前會一直進行等待,不會將控制權交給程式。套接字預設為阻塞模式。可以通過多執行緒技術進行處理。 * 非阻塞模式:執行I/O操作時,Winsock函式會返回並交出控制權。這種模式使用起來比較複雜,因為函式在沒有
非阻塞套接字用法
http://www.cppblog.com/yunboy4/archive/2010/03/16/91231.html 1.非阻塞套接字的模式 (1)伺服器端 通常socket執行後預設為阻塞模式。要呼叫ioctlsocket函式設定非阻塞模式。 如:
accept中的監聽套接字和已連線套接字
int accept(int sockfd, struct sockaddr* cliaddr, socklen_t *addrlen); 該函式用於從已完成連線的佇列隊頭返回下一個已完成連線。 其中sockfd為監聽套接字 cliaddr和addrlen由核心填入
socket套接字和驅動繫結分析
1. socket()系統呼叫 socket系統呼叫是哪個:socket()有3個引數,因此搜尋SYSCALL_DEFINE3,然後在檢索socket即可。 SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) sock
19-高階I/O函式——套接字和標準I/O
之前我們一直使用的read,write函式以及它們的變體recv, send等函式執行I/O,這些函式都是要使用描述符的,通常這些函式都作為unix核心中的系統呼叫實現。 除了以上說的系統呼叫,我們也可以使用標準I/O函式庫(standard I/O libary),這個函式庫由 ANSI
多路複用與多路分解;UDP報文段格式;套接字和埠號
UDP套接字(目的IP地址,目的埠號),若兩個UDP報文段有不同源IP地址和/或源埠號,但有相同目的IP地址和目的埠號,則這兩個報文段將通過相同的套接字被定向到相同的目的程序。TCP套接字(源IP地址,源埠號,目的IP地址,目的埠號),當一個TCP報文段從網路到達一臺主機時,
理解套接字和埠
1 套接字程式設計基礎 套接字,英文為socket,是一種雙向的通訊埠。位於網路中的主機通過連線的套接字提供的介面進行資料傳輸。本節將主要介紹使用套接字進行程式設計的一些基本概念。 1.1 套接字與埠 套接字是一種使用標準UNIX檔案描述符(file descr
TCP如何區分監聽套接字和已連線套接字???
2.10 TCP埠號與併發伺服器 併發伺服器中主伺服器迴圈通過派生一個子程序來處理每個新的連線。如果一個子程序繼續使用伺服器眾所周知的埠來服務一個長時間的請求,那將發生什麼?讓我們來看一個典型的序列。首先,在主機freebsd上啟動伺服器,該主機是多宿的,其IP地址為12.106.32.254和192.1
sanic官方文檔解析之websocket(網絡套接字)和handle decorators(處理程序裝飾器)
test decorator 方法 實例化 con tco nic max cor 1,websocket(網絡套接字) 在websocket上Sanic提供了一種簡單使用的抽象化,來設置websocket(網絡套接字) from sanic import Sanic
套接字的阻塞和非阻塞send/recv
先理一下阻塞和非阻塞的概念: 阻塞就是讓當前呼叫執行緒一直處於停止等待當中,掛起的狀態,執行緒函式會被卡住。 非阻塞則是不管執行結果如何,都會繼續往下執行(往往都要處理很多返回結果),執行緒函式裡一般都是一個迴圈,不停的輪詢。 再理一下發送接收函式: send/sendt
設置非阻塞的套接字Socket
api pad def while循環 ace 使用方法 小時 acc 使用 當使用socket()函數和WSASocket()函數創建套接字時,默認都是阻塞的。在創建套接字之後,通過調用ioctlsocket()函數,將該套接字設置為非阻塞模式。函數的第一個參數是套接字
套接字設定為(非)阻塞模式
當socket 進行TCP 連線的時候(也就是呼叫connect 時),一旦網路不通,或者是ip 地址無效,就可能使整個執行緒阻塞。一般為30 秒(我測的是20 秒)。如果設定為非阻塞模式,能很好的解決這個問題,我們可以這樣來設定非阻塞模式:呼叫 ioctl 函式: unsigned long flag=1;
34.非阻塞丶套接字異常處理丶埠掃描
非阻塞及套接字異常處理: 套接字異常捕獲: 套接字建立失敗,8000 socket.error 客戶端連線錯誤:
在io複用中把監聽套接字設為非阻塞
往往在select 或 epoll 中把 listen_socket 設定為非阻塞 O_NONBLOCK 原因是出在 accept 上, 比如有這麼一個客戶端 : RST客戶端 當這個select或epoll 的伺服器非常繁忙時, 有這麼一個一連線就斷開的客戶端,
套接字的阻塞與非阻塞
套接字的預設狀態是阻塞。阻塞的套接字呼叫可分為四種 (1),輸入操作,包括read,readv,recv,recvfrom,recvmsg。 阻塞: TCP:如果接收緩衝區沒有資料讀,則阻塞,直到資料到達。 UDP:如果接收緩衝區沒有資料讀,則阻塞,直到UDP資料報到