1. 程式人生 > >嵌入式linux網路程式設計,UNIX域套接字,AF_LOCAL,PF_LOCAL,PF_UNIX,,AF_UNIX,程序間通訊機制

嵌入式linux網路程式設計,UNIX域套接字,AF_LOCAL,PF_LOCAL,PF_UNIX,,AF_UNIX,程序間通訊機制

文章目錄

1,UNIX域套接字

用於本地程序間的通訊

  1. socket同樣可以用於本地通訊
  2. 建立套接字時使用本地協議PF_UNIX(或PF_LOCAL)。
    ·socket(AF_LOCAL, SOCK_STREAM, 0) /流式套接字
    /
    · socket(AF_LOCAL, SOCK_DGRAM, 0) /資料報套接字/

PF_INET 和 AF_INET的區別:http://blog.sina.com.cn/s/blog_8043547601013eoc.html
所以在windows中AF_INET與PF_INET完全一樣
而在Unix/Linux系統中,在不同的版本中這兩者有微小差別
對於BSD,是AF,對於POSIX是PF

  1. 分為流式套接字和使用者資料報套接字
  2. 和其他程序間通訊方式相比使用方便、效率更高
  3. 常用於前後臺程序通訊
Linux下的程序間通訊機制 應用
早期UNIX程序間通訊方式
(很多是從Unix繼承的)
無名管道(pipe) 本地通訊,用於一臺計算機內部不同程序之間的通訊
有名管道 (fifo)
訊號(signal)
System V IPC
(系統5的IPC機制)
共享記憶體(share memory)
訊息佇列(message queue)
訊號燈集(semaphore set)
套接字(socket) 既可以進行本地通訊,更多的是多臺主機之間通過網路通訊
易用性:訊息佇列 > unix域套接字 > 管道 > 共享記憶體(經常要和訊號量一起使用)
效率:共享記憶體 > unix域套接字 > 管道 > 訊息佇列
常用:共享記憶體、unix域套接字 非同步通訊:訊號 同步和互斥(做資源保護):訊號量
  1. 本地地址結構
    struct sockaddr_un // <sys/un.h>
    {
    sa_family_t sun_family;
    char sun_path[108]; // 套接字檔案的路徑
    };
  2. 填充地址結構
    struct sockaddr_un myaddr;
    bzero(&myaddr, sizeof(myaddr));
    myaddr.sun_family = AF_UNIX; strcpy(myaddr.sun_path, “/tmp/mysocket”);

2,UNIX域套接字模型

應用程式 UNIX域(流式)套接字 UNIX域(使用者資料報)套接字
伺服器端
客戶端
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
  • 此處addr是一個本地地址,結構體為struct sockaddr_un
#define UNIX_PATH_MAX    108  //大小為96~108

struct sockaddr_un {
     sa_family_t sun_family;               /* AF_UNIX */
     char        sun_path[UNIX_PATH_MAX];  /* pathname */
 };
  • pathname 為域套接字的檔案路徑
    ·必須事先不存在(臨時在記憶體中建立一個檔案)
    ·一般是絕對路徑

3,UNIX域套接字 — 示例

3.1,net.h

#ifndef __NET_H__
#define __NET_H__

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/un.h>

#define UNIX_DOMAIN_FILE "/tmp/my_domain_file.1"
#define BACKLOG 5
#define QUIT_STR "quite"
#define SERV_RESP_STR "Server:"

#endif

3.2,client.c

/* ./client unix_domaun_file */
#include "net.h"

void usage(char *s)
{
	printf("Usage: %s <unix_domaun_file>\n",s);
}
int main(int argc, const char *argv[])
{
	int fd;
	if(argc != 2)
	{
		usage((char *)argv[0]);
		exit(1);
	}
	/* 1 建立socket fd */
	if((fd = socket(AF_LOCAL,SOCK_STREAM,0)) < 0)
	{
		perror("socket");
		exit(-1);
	}
	
	/* 2 連線伺服器 */
	/* 2.1 填充struct sockaddr_un結構體變數*/
    struct sockaddr_un sun;
	bzero(&sun,sizeof(sun));
	sun.sun_family = AF_LOCAL;

	/*  確保UNIX_DOMAun_FILE所指向的檔案存在且可寫,否則退出 */
	if(access(UNIX_DOMAIN_FILE,F_OK|W_OK) < 0)
	{
		exit(-1);
	}
	strncpy(sun.sun_path,argv[1],strlen(argv[1]));
	/* 2.2 連線伺服器*/
	if(connect(fd,(struct sockaddr *)&sun,sizeof(sun)) < 0)
	{
		perror("connect");
		goto _error1;
	}
	printf("client starung ... OK!\n");

	fd_set rset;
	int maxfd;
	struct timeval tout;
	char buf[BUFSIZ];
	int ret = -1;
	while(1)
	{
		FD_ZERO(&rset);

		FD_SET(0,&rset);
		FD_SET(fd,&rset);
		maxfd = fd;
		tout.tv_sec = 5;
		tout.tv_usec = 0;

		select(maxfd+1,&rset,NULL,NULL,&tout);
		if(FD_ISSET(0,&rset))//標準輸入裡面是不是有輸入
		{
			/* 讀取鍵盤輸入,傳送到網路套接字fd */
			bzero(buf,BUFSIZ);
			do 
			{
				ret = read(0,buf,BUFSIZ-1);
			}while(ret <0 && EINTR == errno);
			if(ret < 0)
			{
				perror("read");
				continue ;
			}
			if(ret == 0)//沒讀到資料
			{
				continue;
			}
			if(write(fd,buf,strlen(buf)) < 0)
			{
				perror("write() to socket");
				continue ;
			}
			if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0)//退出在傳送之後
			{
				printf("client is existung!\n");
				break;
			}
		}
		if(FD_ISSET(fd,&rset))//伺服器傳送了資料過來
		{
			/* 讀取套接字資料,處理 */
			bzero(buf,BUFSIZ);
			do 
			{
				ret = read(fd,buf,BUFSIZ-1);
			}while(ret <0 && EINTR == errno);
			if(ret < 0)
			{
				perror("read from socket");
				continue ;
			}
			if(ret == 0)//從套接字中讀到的資料個數小於0,說明伺服器關閉
			{
				break ;
			}
			printf("server said: %s",buf);
			if((strlen(buf) > strlen(SERV_RESP_STR)) && strncasecmp(buf+strlen(SERV_RESP_STR),QUIT_STR,strlen(QUIT_STR)) == 0)
			{
				printf("sender client is existung!\n");
				break;
			}
		}
	}

_error1:
	close(fd);
	return 0;
}

3.3,sever.c

#include "net.h"
#include "linklist.h"
#include <sys/ioctl.h>

/* IO多路複用select()處理函式 */
void do_select(int fd);

int main(int argc, const char *argv[])
{
	int fd;

	/* 1 建立socket fd */
	if((fd = socket(AF_LOCAL,SOCK_STREAM,0)) < 0)//基於本地的TCP通訊
	{
		perror("socket");
		exit(-1);
	}
	/* 優化 1 允許繫結地址快速重用 */ 
	int b_reuse = 1;
	setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int)); 
	
	/* 2.2 繫結*/
	/* 2.1 填充struct sockaddr_un 結構體變數*/
    struct sockaddr_un sun;
	bzero(&sun,sizeof(sun));

	sun.sun_family = AF_LOCAL;
	
	/*  如果UNIX_DOMAun_FILE所指向的檔案存在,則刪除 */
	if(access(UNIX_DOMAIN_FILE,F_OK))
	{
		unlink(UNIX_DOMAIN_FILE);//刪除該檔案	
	}
	strncpy(sun.sun_path,UNIX_DOMAIN_FILE,strlen(UNIX_DOMAIN_FILE));
	/* 2.2 繫結*/
	if(bind(fd,(struct sockaddr *)&sun,sizeof(sun)))
	{
		perror("bind");
		goto _error1;
	}

	/* 3 使用listen()把主動套接字變成被動套接字 */
	if(listen(fd,BACKLOG) < 0)
	{
		perror("listen");
		goto _error1;
	}
	
	do_select(fd);

_error1:
	close(fd);
	return 0;
}


void do_select(int fd)
{
	linklist fdlist,sun_list;//建立一個列表,用於檔案描述符及客戶端資訊儲存
	fdlist = create_linklist();
	datatype sun_data;//每個物件包括客戶端的socket fd,ipv4地址,埠號
	sun_data.fd = fd;
	int maxfd = fd;
	//struct timeval tout = {5,0};

	insert_end_linklist(fdlist,sun_data);//將lsten()處理後的fd加入列表
	//show_linklist(fdlist);
	
	fd_set rset;
	int newfd = -1;
	int ret = -1;
	char buf[BUFSIZ];//BUFSIZ是系統提供的
	char resp_buf[BUFSIZ+10];
	struct sockaddr_un cun;
	socklen_t cun_addr_len = sizeof(cun);
	/* 用select()函式實現I/O多路複用*/
	while(1)
	{
		int i;
		FD_ZERO(&rset);
		if(get_length_linklist(fdlist) >= 1)//將列表中的fd加入讀集合進行處理
		{
				//puts("11111111111111111111111111111");
			for(i=0;i<get_length_linklist(fdlist);i++)
			{
				sun_list = get_list_pos_linklist(fdlist,i);
				sun_data = sun_list->data;
				FD_SET(sun_data.fd,&rset);
				maxfd = sun_data.fd > maxfd ? sun_data.fd : maxfd;
				//printf("第 %d 個(fd:%d)(ip:%s)(port:%d)\n",i,sun_data.fd,sun_data.ipv4_addr,sun_data.port);
			}
			//show_linklist(fdlist);
		}
		else
		{
			continue ;
		}
		//switch(select(maxfd+1,&rset,NULL,NULL,&tout))
		switch(select(maxfd+1,&rset,NULL,NULL,NULL))
		{
			case 0:
			{
				printf("time out!\n");
				goto _error1;
			}
			case -1:
			{
				perror("select");
				goto _error1;
			}
			default:
			{
				if(FD_ISSET(fd,&rset))//有客戶端傳送了連線請求
				{
					if((newfd = accept(fd,(struct sockaddr *)&cun,&cun_addr_len)) < 0)
					{
						perror("connect");
						goto _error1;
					}
					/* 將分配成功的套接字newfd設定成非阻塞模式*/
					int b_on = 1;
   					ioctl(newfd, FIONBIO, &b_on);//將分配成功的套接字newfd設定為非阻塞方式
					sun_data.fd = newfd;
					printf("get a new client->(ip:%s)(port:%d)(fd:%d)\n",sun_data.ipv4_addr,sun_data.port,sun_data.fd);
					
					insert_end_linklist(fdlist,sun_data);//將建立客戶端連線的fd加入列表
					//show_linklist(fdlist);
				}
				else//有連線好的客戶端傳送了資料
				{
					//puts("22222222222222222222");
					for(i=0;i<get_length_linklist(fdlist);i++)//將連結串列中的fd都處理一遍
					{
						
						sun_list = get_list_pos_linklist(fdlist,i);
						sun_data = sun_list->data;
						//printf("readung fd is ->(第 %d 個)(fd:%d)(ip:%s)(port:%d)\n",i,sun_data.fd,sun_data.ipv4_addr,sun_data.port);
						if(sun_data.fd == fd)//不是建立連線後分配的newfd
							continue ;
						//puts("########read before");
						bzero(buf,BUFSIZ);
						do
						{
							ret = read(sun_data.fd,buf,BUFSIZ-1);
						}while(ret < 0 && errno == EINTR);//阻塞讀寫
						
						if(ret < 0)
						{
							//perror("read");
							continue;
						}
						if(ret == 0)//對方已關閉
						{
							printf("client is existung!\n");
							delete_locate_linklist(fdlist,sun_data);
							continue;
						}

						printf("client ip(:%s) port(:%d) fd(:%d) receive data: %s",sun_data.ipv4_addr,sun_data.port,sun_data.fd,buf);
					
						bzero(resp_buf,BUFSIZ+25);
						strncpy(resp_buf,SERV_RESP_STR,strlen(SERV_RESP_STR));
						strcat(resp_buf,"ip(");
						strcat(resp_buf,sun_data.ipv4_addr);
						char s_port[10];
						strcat(resp_buf,"  port(");
						sprintf(s_port,"%d",sun_data.port);
						strcat(resp_buf,s_port);
						strcat(resp_buf,"  data(");
						strcat(resp_buf,buf);
						do
						{
							ret = write(sun_data.fd,resp_buf,strlen(resp_buf));
						}while(ret < 0 && EINTR == errno);
						//puts("###############################");	
						if(strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)) == 0)
						{
							printf("client (fd:%d)(ip:%s)(potr:%d) is existung!\n",sun_data.fd,sun_data.ipv4_addr,sun_data.port);
							delete_locate_linklist(fdlist,sun_data);//將退出的客戶端的fd從列表中刪除
							close(sun_data.fd);
							//show_linklist(fdlist);
						}
					}
				}			
			}
		}
	}

	close(newfd);
_error1:
	close(fd);
	clear_linklist(fdlist);

}

3.4,linklist.h

#ifndef __SINGLE_LINKLIST_H__
#define __SINGLE_LINKLIST_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

typedef struct{
	int fd;
	char ipv4_addr[16];
	int port;
}datatype;

typedef struct node{
	datatype data;
	struct node *next;
}listnode,*linklist;

linklist create_linklist(void);
linklist create_n_linklist(void);
int delete_pos_linklist(linklist L,int pos);
int delete_locate_linklist(linklist L,datatype x);
void clear_linklist(linklist L);

int get_length_linklist(linklist L);
linklist get_list_pos_linklist(linklist L,int pos);
linklist get_list_locate_linklist(linklist L,datatype x);

int insert_head_linklist(linklist L,datatype x);
int insert_n_head_linklist(linklist L);
int insert_end_linklist(linklist L,datatype x);
int insert_n_end_linklist(linklist L);
int insert_pos_linklist(linklist L,datatype x,int pos);
int insert_order_linklist(linklist L,datatype x
            
           

相關推薦

嵌入式linux網路程式設計UNIXAF_LOCALPF_LOCALPF_UNIXAF_UNIX程序通訊機制

文章目錄 1,UNIX域套接字 2,UNIX域套接字模型 3,UNIX域套接字 --- 示例 3.1,net.h 3.2,client.c 3.3,sever.c 3.4,linklist.h 3.5,link

linux網路程式設計之socket(十六):通過UNIX傳遞描述符和 sendmsg/recvmsg 函式

void send_fd(int sock_fd, int send_fd) {     int ret;     struct msghdr msg;     struct cmsghdr *p_cmsg;     struct iovec vec;     char cmsgbuf[CMSG_SPACE(

UNIX網路程式設計卷1:聯網API 詳解筆記

UNIX網路程式設計卷1:套接字聯網API 詳解筆記 第一部分:簡介和TCP/IP 1.Socket 套接字 sockfd = socket(AF_INET(網際流), SOCK_STREAM, 0); 2.*bind(int fd, const struct sockaddr sa,

go語言unix發送udp報文

dial ring pack sock world lis add client 語言 /* server.go */package mainimport ( "fmt" "net" &quo

【Nebula系列】通過UNIX傳遞描述符的應用

_file__ 直接 sca linux網絡 tran 和數 權限 cif .cpp ??傳送文件描述符是高並發網絡服務編程的一種常見實現方式。Nebula 高性能通用網絡框架即采用了UNIX域套接字傳遞文件描述符設計和實現。本文詳細說明一下傳送文件描述符的應用。 1. T

通過UNIX傳遞文件描述符

and starting github option nts wiki 靜態方法 socket union 傳送文件描述符是高並發網絡服務編程的一種常見實現方式。Nebula 高性能通用網絡框架即采用了UNIX域套接字傳遞文件描述符設計和實現。本文詳細說明一下傳送文件描述符

網路程式設計(二)---------------------------詳解

前文有介紹,網路資料的傳輸是通過套接字來實現的,套接字共有3種類型:流式套接字(SOCK_STREAM),資料報套接字(SOCK_DGRAM)和原始套接字(RAW)。在本文中將蛀牙介紹流式套接字與資料包套接字、 一、流式套接字        流式套接字是面向連線的,提供雙

20-unix地址結構

1. unix域協議 看到這個標題,不知道的小夥伴肯定以為這是一個協議族之類的,但實際上unix域協議是在單臺主機上客戶端與服務端之間的通訊方法,簡單來說,unix域協議也是一種程序間通訊方式,用於同一臺主機上的客戶端和服務端,為不同的程序間傳遞描述符。 通常在同一臺主機上,使用unix

程序筆記2:程序之間的通訊UNIXsocket)

socket的地址資料結構根據不同的系統以及網路環境有不同形式。為了使不同格式地址能夠被傳入套接字函式,必須強制將地址結構轉換為: struct sockaddr{ sa_family_t sa_family; /* address family*/ char

UNIX中的抽象名字空間

原文地址:http://blog.chinaunix.net/uid-317451-id-92602.html UNIX域(PF_UNIX、PF_LOCAL或AF_UNIX、AF_LOCAL)套接字為UNIX系統的本地程序間的雙向資料通訊提供了高效的解決方案。 我們可以認為

使用Unix進行跨程序通訊

Unix域套接字簡介 《Unix環境高階程式設計》中對Unix域套接字有如下介紹: 雖然socketpair函式建立相互連線的一對套接字,但是每一個套接字都沒有名字。這意味著無關程序不能使用它們。 我們可以命名unix域套接字,並可將其用於告示服務。但是要

【TCP/IP網路程式設計】:09的多種可選項

本篇文章主要介紹了套接字的幾個常用配置選項,包括SO_SNDBUF & SO_RCVBUF、SO_REUSEADDR及TCP_NODELAY等。 套接字可選項和I/O緩衝大小 前文關於套接字的描述僅僅是使用其預設套接字特性來進行資料通訊,這對於簡單的使用場景來說似乎是可以的,然而實際工作場景中的確需要

嵌入式Linux網路程式設計網路基礎socket(SOCK_STREAM、SOCK_DGRAM、SOCK_RAW)IP地址埠號位元組序位元組序轉換函式IP地址的轉換

文章目錄 1,socket 1.1,socket的型別(SOCK_STREAM、SOCK_DGRAM、SOCK_RAW) 1.2,socket的位置 2,IP地址 2.1,特殊IP地址: 3,埠號

嵌入式linux網路程式設計廣播組播

文章目錄 1,廣播 1.1,廣播收發 1.2,廣播收發---示例 1.2.1,net.h 1.2.2,sender.c 1.2.3,receiver.c 1.2.4,執行結果

嵌入式linux網路程式設計網路資訊檢索函式域名解析gethostbyname()網路屬性設定setsockopt()網路超時優化心跳檢測

文章目錄 1,網路資訊檢索函式 2,域名解析 2.1,gethostbyname() 2.2,gethostbyaddr() 2.3 錯誤處理 herror()、hstrerror() 2.4 釋放hostent結構體end

嵌入式linux網路程式設計TCP、IP協議原理wireshark抓包工具乙太網頭(Ethernet header)IP頭TCP頭三次握手四次握手UDP頭

文章目錄 1,wireshark抓包工具 1.1,wireshark安裝 1.2,wireshark啟動 1.2.1,出現錯誤警告 1.2.2,解決方案 2,常用除錯測試工具 3,TCP

嵌入式Linux網路程式設計I/O多路複用epoll()示例epoll()客戶端epoll()伺服器單鏈表

文章目錄 1,I/O多路複用 epoll()示例 1.1,epoll()---net.h 1.2,epoll()---client.c 1.3,epoll()---sever.c 1.4,epoll()---linklist.h

嵌入式Linux網路程式設計I/O多路複用poll()示例poll()客戶端poll()伺服器單鏈表

文章目錄 1,IO複用poll()示例 1.1,poll()---net.h 1.2,poll()---client.c 1.3,poll()---sever.c 1.4,poll()---linklist.h 1.5,p

嵌入式Linux網路程式設計I/O多路複用select()示例select()客戶端select()伺服器單鏈表

文章目錄 1,IO複用select()示例 1.1 select()---net.h 1.2 select()---client.c 1.3 select()---sever.c 1.4 select()---linklist.h

嵌入式Linux網路程式設計I/O多路複用阻塞I/O模式非阻塞I/O模式fcntl()/ioctl()多路複用I/O select()/pselect()/poll()訊號驅動I/O

文章目錄 1,I/O模型 2,阻塞I/O 模式 2.1,讀阻塞(以read函式為例) 2.2,寫阻塞 3,非阻塞模式I/O 3.1,非阻塞模式的實現(fcntl()函式、ioctl() 函式)