liunx 多進程不阻塞I/O

思路

  多進程的特性是複製父進程的所有數據,這和多線程的公用內存不一樣,多進程的好處在於不容易出現一些麻煩的內存問題,多線程的互斥是一件很麻煩的事情,當然也因爲這樣,多進程也擁有自己的侷限性。

  利用 多進程+阻塞I/O 的方式實現不阻塞I/O,簡單來說就是每accept到一個新的連接,就創建一個子進程,通過那個子進程來單方面通信,子進程裏面還是用的最簡單的阻塞I/O,這樣的話就能實現維護多用戶同時連接的問題,當然這樣還是不能實現異步I/O,想要實現異步I/O的話,可以在子進程裏面創建一個子線程,主線程加子線程就可以實現異步I/O,我這裏只是一個簡單的實現,前後不過花了我十幾分鍾時間,所以沒加多線程的內容。

  子進程複製了父進程的數據,所以可以利用父進程裏面的套接字和sockaddr。


代碼實現

我這裏是用的標準C寫的,沒有C/C++混寫,寫得比較醜,因爲只是一個簡單的demo,所以沒有考慮代碼風格的問題

/*********************************************************
 * Author			: crazy_mad
 * Last modified	: 2017-01-16 15:39
 * Filename			: main.c
 * Description		: 
 *********************************************************/

#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

#define BUF_LENGTH 256  	// buf長度

int main(int argc, char* argv[])
{	
	int on = 1;
	int server_fd = socket(AF_INET, SOCK_STREAM, 0);
	// 設置socket模式,這裏主要是設置的tcp和重複使用地址
	if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
		printf("setsockopt error: %s\n", strerror(errno));
		exit(1);
	}
	socklen_t len = sizeof(struct sockaddr_in);
	struct sockaddr_in server_addr, client_addr;		// 客戶端、服務端地址信息
	server_addr.sin_family = AF_INET;					
	server_addr.sin_port = htons(8001);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	// 綁定地址
	if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
		printf("bind error: %s\n", strerror(errno));
		exit(1);
	}

	memset(&client_addr, 0, sizeof(client_addr));
	listen(server_fd, 10);
	while (1) {
		int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &len);
		char buf[BUF_LENGTH] = { 0 };

		// 創建子進程
		pid_t child = fork();
		int status;
		if (child == -1) {	 		// 創建子進程失敗
			perror("fork");
			exit(EXIT_FAILURE);
		} else if (child == 0) {	// 創建子進程成功
			printf("child pid=%d ppid=%d created\n", getpid(), getppid());
			int ret;
			while (1) {
				ret = recv(client_fd, buf, BUF_LENGTH, 0);
				if (ret <= 0) {		// socket連接斷開(或其他異常)
					break;
				}
				printf("%s\n", buf);
			};
			printf("child pid=%d exit!\n", getpid());
			close(client_fd);		// 回收客戶端套接字
			exit(EXIT_SUCCESS);
		} else {					// 子進程成功退出
			//printf("parent pid=%d ppid=%d\n", getpid(), getppid());
			int w = waitpid(child, &status, WUNTRACED | WCONTINUED);
			if (w == -1) {			// 子進程退出異常
				perror("waitpid");
				exit(EXIT_FAILURE);
			} else {				// 子進程正常退出
				//printf("child exited\n");
			}
		}
	}

	close(server_fd);				// 回收套接字
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章