1. 程式人生 > >epoll示例程式——服務端

epoll示例程式——服務端

原始碼:

#include <sys/epoll.h> 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
//返回值的巨集定義,在開發linux環境時,用0表示成功
#define RES_SUC 0
#define RES_FAIL -1

#define FD_NULL 0
#define null 0
#define MAX_EPOLL_FD 1024
#define LISTEN_SOCK_QUEUE 1024

#define WORK_STATE_STOP 0
#define WORK_STATE_RUN 1
//伺服器的監聽埠
#define LISTNE_PORT 3557

#define INVALID_SOCKET -1

#define MAX_EPOLL_EVENTS 1024
//epoll在無事件發生時的最大返回間隔時間
#define EPOLL_WAIT_INTERVAL 100 

#define  MAX_BUF_SIZE_READ 1024

static int g_fd_epoll = FD_NULL;
static int g_fd_listen_sock = FD_NULL;
static int g_run_server = WORK_STATE_RUN;
int main()
{
	printf("[main] will start test server!\n");
	//初始化測試伺服器
	if(init() == RES_FAIL)
	{
		printf("[main] init fail!\n");
		return RES_FAIL;
	}
	// 開始長迴圈工作
	if(main_loop() == RES_FAIL)
	{
		printf("[main] main_loop fail!\n");
		return RES_FAIL;
	}
	printf("[main] test server will exit!\n");
	return RES_SUC;
}
/**
*初始化服務端程式,成功返回RES_SUC
*/
int init()
{
	//建立epoll的控制代碼
	g_fd_epoll = epoll_create(MAX_EPOLL_FD);
	if(g_fd_epoll <= 0)
	{
		printf("[init] epoll_create fail!\n");
		return RES_FAIL;
	}
	//初始化監聽socket
	if(init_listen_socket() == RES_FAIL)
	{
		printf("[init] epoll_create fail!\n");
		return RES_FAIL;
	}
	
	return RES_SUC;
}
/*
*初始化監聽socket,成功則返回建立的監聽socket,否則返回RES_FAIL
*/
int init_listen_socket()
{
	printf("[init_listen_socket] will init listen socket!\n");
	//建立監聽socket的控制代碼
	g_fd_listen_sock = socket(AF_INET, SOCK_STREAM, 0);
	if(INVALID_SOCKET == g_fd_listen_sock)
	{
		printf("[init_listen_socket] create listen socket fail!\n");
		return RES_FAIL;
	}
	//設定監聽socket的狀態為非阻塞
	int opt = 1;
	opt = fcntl(g_fd_listen_sock, F_GETFL, 0);
	if(opt == -1 || fcntl(g_fd_listen_sock, F_SETFL, opt | O_NONBLOCK) == -1)
	{
		printf("[init_listen_socket] set socket state: O_NONBLOCK fail!\n");
		close(g_fd_listen_sock);
		return RES_FAIL;
	}
	
	//繫結socket到本地埠
	struct sockaddr_in serv_addr;
	serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // 使用本地通配地址
    serv_addr.sin_port = htons(LISTNE_PORT); 
	if(bind(g_fd_listen_sock, (struct sockaddr *)&serv_addr, sizeof( serv_addr)) != RES_SUC)
	{
		printf("[init_listen_socket] bind socket to port %d fail!\n", LISTNE_PORT);
		close(g_fd_listen_sock);
		return RES_FAIL;
	}
	//開啟socket的監聽狀態
	if(listen(g_fd_listen_sock, LISTEN_SOCK_QUEUE) == -1)
	{
		printf("[init_listen_socket] listen socket fail!\n");
		close(g_fd_listen_sock);
		return RES_FAIL;
	}
	
	//註冊監聽socket到epoll
	if(reg_socket(g_fd_listen_sock) == RES_FAIL)
	{
		printf("[init_listen_socket] reg_socket fail!\n");
		return RES_FAIL;
	}
	printf("[init_listen_socket] init listen socket suc!\n");
	return g_fd_listen_sock;
}
//註冊一個socket到epoll
int reg_socket(int new_sock)
{
	if(new_sock <= 0)
		return RES_FAIL;
	struct epoll_event new_events;
	new_events.data.fd = new_sock;
	new_events.events = EPOLLIN;//我們只關注有資料到來
	if(epoll_ctl(g_fd_epoll, EPOLL_CTL_ADD,new_sock, &new_events) < 0){
		printf("[reg_socket] register socket into epoll faill!\n");
		return RES_FAIL;
	}
	else		
		return RES_SUC;				
}
//主迴圈體
int main_loop()
{
	//建立一個epoll事件的緩衝區,以便存放就緒的檔案描述符
	struct epoll_event* epoll_events = null;
	epoll_events = (struct epoll_event*)malloc(sizeof(struct epoll_event) * MAX_EPOLL_EVENTS);
	if(epoll_events == null)
	{
		printf("[main_loop] allocating memory for epoll events faill!\n");
		return RES_FAIL;
	}
	int fd_ready_num = 0;
	printf("[main_loop] server start success at port:%d!\n", LISTNE_PORT);
	while(g_run_server == WORK_STATE_RUN)
	{
		//使用epoll來監控所有註冊進來的socket,該步驟將以阻塞的方式用epoll_wait等待就緒的描述符,當一直沒有描述符就緒時,最多將等待EPOLL_WAIT_INTERVAL毫秒之後,也會返回;
		fd_ready_num = epoll_wait(g_fd_epoll, epoll_events, MAX_EPOLL_EVENTS, EPOLL_WAIT_INTERVAL);
		//epoll_wait返回時說明有就緒的socket或者等待的超時時間到了
		int i = 0;
		for(i = 0; i < fd_ready_num; i++)
		{
			if(epoll_events[i].data.fd == g_fd_listen_sock)
			{//說明當前的描述符是一個監聽socket
				if(handle_listen_socket() == RES_FAIL)
				{
					printf("[main_loop] handle listen socket faill!\n");
				}
				continue;
			}
			//以下步驟將處理業務socket
			if(handle_business_socket(epoll_events[i].data.fd) == RES_FAIL)
			{
				printf("[main_loop] handle business socket:%s faill!\n", epoll_events[i].data.fd);
			}
		}
	}
}

//處理就緒的監聽socket,接收新的連線進來,併為之產生一個業務socket
int handle_listen_socket()
{
	int new_sock = INVALID_SOCKET;
	new_sock = accept(g_fd_listen_sock, NULL, 0);
	if(new_sock == INVALID_SOCKET)
	{
		printf("[handle_listen_socket] accept new socket faill!\n");
		return RES_FAIL;
	}
		
	//設定監聽socket的狀態為非阻塞
	int opt = 1;
	opt = fcntl(new_sock, F_GETFL, 0);
	if(opt == -1 || fcntl(new_sock, F_SETFL, opt | O_NONBLOCK) == -1)
	{
		printf("[handle_listen_socket] set socket state: O_NONBLOCK fail!\n");
		close(new_sock);
		return RES_FAIL;
	}
	
	//註冊監聽socket到epoll
	if(reg_socket(new_sock) == RES_FAIL)
	{
		printf("[handle_listen_socket] reg_socket:%d fail!\n", new_sock);
		return RES_FAIL;
	}
	printf("[handle_listen_socket] accept new socket:%d suc!\n", new_sock);
	return RES_SUC;
}

//處理就緒的業務socket
int handle_business_socket(int ready_socket)
{
	if(ready_socket == INVALID_SOCKET)
	{
		printf("[handle_business_socket] socket:%d is invalid!\n", ready_socket);
		return RES_FAIL;
	}
	char* read_buf = (char* )malloc(sizeof(char) * MAX_BUF_SIZE_READ);
	memset(read_buf, '\0', MAX_BUF_SIZE_READ);
	int read_len = read(ready_socket, read_buf, MAX_BUF_SIZE_READ);
	if(read_len > 0)
	{
		printf("[handle_business_socket] recv msg from socket:%d, content:%s\n", ready_socket, read_buf);
		if(write(ready_socket, read_buf, read_len) != read_len)
		{
			printf("[handle_business_socket] write msg into socket:%d fail! content:[%s]!\n", ready_socket, read_buf);
		}
	}
	free(read_buf);
}

按照如下方式編譯並執行:
[[email protected] echoserver]# gcc echo_server.c -o echo_server
[[email protected] echoserver]# ./echo_server 
[main] will start test server!
[init_listen_socket] will init listen socket!
[init_listen_socket] init listen socket suc!
[main_loop] server start success at port:3557!


相關推薦

epoll示例程式——服務

原始碼: #include <sys/epoll.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h&

多執行緒版本TCP聊天程式服務

   這是一個通過多執行緒來實現可以接受多個客戶端的TCP聊天程式。    //這是一個實現多執行緒TCP的聊天程式服務端 #include<stdio.h> #include<stdlib.h> #includ

多程序版本TCP聊天程式服務

  我們上次寫了利用TCP協議來實現的簡單的網路聊天程式,我們實現的是一對一的聊天, 但是如果我們通過上次的程式來實現多對一呢?     我們可以看出來其中一個客戶端可以和服務端正常交流,但是另一個客戶端是連結不上服務端的,即

微信小程式服務請求必須HTTPS 微信小程式服務請求必須HTTPS

微信小程式服務端請求必須HTTPS SSL證書的作用 HTTP明文協議是不安全的傳輸協議,無法進行伺服器端真實身份校驗,也不能為傳輸資料提供加密保護,通過HTTP協議傳輸的資料時刻處在被竊聽、篡改、冒充的風險

Vue+koa2開發一款全棧小程式(服務環境搭建和專案初始化)

1.微信公眾平臺小程式關聯騰訊雲 騰訊雲的開發環境是給免費的一個後臺,但是隻能夠用於開發,如果用於生產是需要花錢的,我們先用開發環境吧 1.用小程式開發郵箱賬號登入微信公眾平臺 2.【設定】→【開發者工具】→第一次是git管理,開啟騰訊雲關聯 3.會一路跳轉到騰

3步搭建微信小程式服務環境筆記

本實踐筆記基於nginx+uwsgi+django 2,在django專案根目錄下建立wechatapp_wsgi_debug.ini和wechatapp_wsgi.ini wechatapp_wsgi_debug.ini [uwsgi] # Dja

程式服務整合微信支付

理論上整合微信支付的全部工作可以在小程式端完成,因為小程式js有訪問網路的能力,但是為了安全,不暴露敏感key,也更好地跨平臺(對於iOS與Android原生APP開發來說,哪天小程式的支付介面也納入了開放平臺了,這條也就成立了),而且可以使用官方提供的現成php dem

python使用epoll實現的服務例子

#!/usr/bin/python # -*- coding: UTF-8 -*- import socket import select send_data = "hello world!" send_len = len(send_data) recv_le

利用webuploader外掛上傳圖片檔案,完整前端示例demo,服務使用SpringMVC接收

利用WebUploader外掛上傳圖片檔案完整前端示例demo,服務端使用SpringMVC接收 Webuploader簡介   WebUploader是由Baidu WebFE(FEX)團隊開發的一個簡單的以HTML5為主,FLASH為輔的現代檔案上傳元件。在現代的瀏覽器裡面能充分發揮HTML5的優勢,同

基於select非阻塞模型的服務程式示例(Winsock2實現)

/* 總結: ①無論阻塞還是非阻塞,select都不會立即返回,select就是用於非阻塞模型中的。 ②將SOCKET置於非阻塞模式下時,處理連線或處理收發資料的Socket API都會立即返回。 ③select會監視fd_set中的所有套接字,一旦有套接字發生IO事件(包括客戶端的連

單點登入cas綜述之cas4.2.7服務+cas客戶+示例程式+環境搭建說明-陳杰

3其他說明 1環境搭建以及把示例程式跑起來        一切跑不起來的程式和走不通的教程都是耍流氓,二話不說,先按照我的步驟把程式跑起來在說吧。 1.1安裝JDK1.8       安裝jdk1.8

Python中使用epoll開發服務程式

這是個很簡單的C/S模型的程式,流程其實和C語言相差不大,客戶端傳送字串,服務端再將該字串返回客戶端,epoll中使用的邊緣觸發。

java服務程式部署伺服器以及壓力測試過程

這段時間負責公司的服務端Java程式開發,做了一個遊戲的登入、註冊、支付、token驗證以及相關統計介面的服務端程式。 考慮到遊戲中如果是多使用者的情況下登入註冊介面在開服的時候會產生很大的併發,所以再上線之前做了一些壓力測試。 伺服器配置:亞馬遜雲伺服器8核心、15G記憶體、200G硬碟、

Oauth2.0客戶服務示例

https://blog.csdn.net/qq_28165595/article/details/80459185   前言前面的理解OAuth2.0認證與客戶端授權碼模式詳解,我們大致瞭解了Oauth2.0授權模式四種的授權碼模式,清楚了授權碼模式的大致流程。這裡簡單的模擬一下基於授權碼模式

next.js、nuxt.js等服務渲染框架構建的專案部署到伺服器,並用PM2守護程式

前端渲染: vue、react等單頁面專案應該這樣子部署到伺服器 貌似從前幾年,前後端分離逐漸就開始流行起來,把一些渲染計算的工作拋向前端以便減輕服務端的壓力,但為啥現在又開始流行在服務端渲染了呢?如vue全家桶或者react全家桶,都推薦通過服務端渲染來實現路由。搞得我們慌得不行,不禁讓我想起一

boost::asio伺服器處理多個客戶連線(服務程式)

class talk_to_client //: boost::enable_shared_from_this<talk_to_client> { public:     talk_to_client():m_sock(service),already_r

利用Nuxt.js建立服務渲染的Vue.js應用程式

Nuxt.js 是一個 Vue 同構應用程式開發框架。本文將介紹為什麼要選擇 Nuxt、如何建立一個 Nuxt 專案、Nuxt 專案結構、Nuxt 的強化元件、使用服務端渲染時的考量、Nuxt 在各種環境的部署以及涉及的一些基本概念。希望能夠鼓勵你嘗試 Nuxt 來進行快速開發,並利用 Nu

【微信小程式】c# 實現獲取openid、session_key 服務

c#寫一個獲取微信小程式 openid和session_key 的方法。。 1,微信小程式端 // 登入 wx.login({ success: res => { // 傳送 res.code 到後臺換取 openId, sessionKey,

阿里雲ECS伺服器部署Dart服務程式

pub global activate [package] Instead of this: export PATH="$PATH":"~/.pub-cache/bin" It should be export PATH="$PATH:$HOME/.pub-cache/bin" 1.D

.net服務獲取微信小程式使用者資訊

1 public void RequestWxUserInfo(string code, string iv, string encryptedData, string rawData, string signature) 2 { 3 string res