进程间通信的方式有信号量、共享内存、管道、消息队列、socket和信号。
信号量 PV操作
P -1 <=0 阻塞
V +1 阻塞->运行状态
int semget(key_t key, int num_sems, int sem_flags);
创建或获取一个信号量;
int semctl(int semid,int semnum,int cmd,union semun ctl_arg);
控制信号量
int semop(int semid,struct sembuf*sops,unsign ednsops);
PV操作
参考代码见http://blog.csdn.net/u011641885/article/details/47682421
http://www.cnblogs.com/LZYY/p/3453582.html
无名管道 单向的
创建:int pipe_field[2]; pipe(pipe_field);
销毁:close(pipe_field[0]) 读管道;close(pipe_field[1]) 写管道;
读管道:char buf[len]; memset(buf, 0, sizeof(buf));
Close(pipe_field[1]); read(pipe_field[0], buf, sizeof(buf)); Close(pipe_field[0]);
写管道:Close(pipe_field[0]); write(pipe_field[1], “hello ”, 6); write(pipe_field[1], “world”, 5); Close(pipe_field[1]);
有名管道
int mkfifo(const char *filename, mode_t mode);
创建有名管道
int open(const char *path, O_RDONLY | O_NONBLOCK);
打开管道
res = read(pipe_fd, buffer, PIPE_BUF);
读管道
res = write(pipe_fd, buffer, bytes_read);
写管道
close(pipe_fd);
关闭管道
mkfifo()是创建管道文件的函数,unlink()会删除参数pathname 指定的文件. 如果该文件名为最后连接点, 但有其他进程打开了此文件, 则在所有关于此文件的文件描述词皆关闭后才会删除. 如果参数pathname 为一符号连接, 则此连接会被删除。
示例代码参考http://www.cnblogs.com/fangshenghui/p/4039805.html
共享内存
创建共享内存
int shmget(key_t key, size_t size, int shmflg);
启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间。
void *shmat(int shm_id, const void *shm_addr, int shmflg);
将共享内存从当前进程中分离。注意,将共享内存分离并不是删除它,只是使该共享内存对当前进程不再可用。
int shmdt(const void *shmaddr);
控制共享内存
int shmctl(int shm_id, int command, struct shmid_ds *buf);
删除共享内存
shmctl(shmid, IPC_RMID, 0);
具体读写参考以下链接:
http://blog.csdn.net/ljianhui/article/details/10253345
消息队列
创建消息队列
int msgget(key_t, key, int msgflg);
控制消息队列
int msgctl(int msgid, int command, struct msgid_ds *buf);
接收消息
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
- struct msg_st
- {
- long int msg_type;
- char text[BUFSIZ];
- };
- struct msg_st data; long int msgtype = 0;
- msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0)
发送消息
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
char buffer[BUFSIZ];
- fgets(buffer, BUFSIZ, stdin);
- data.msg_type = 1;
- strcpy(data.text, buffer);
- //向队列发送数据
- if(msgsnd(msgid, (void*)&data, BUFSIZ, 0) == -1)
具体实例参考http://blog.csdn.net/ljianhui/article/details/10287879
信号
信号分为可靠(实时RT)和不可靠信号(非实时)。SIGRTMIN前的为不可靠信号;SIGRTMIN~SIGRTMAX为可靠信号。可靠信号支持排队。
进程PCB中有一个变量用来记录信号信息,结构如下:
struct sigpending{
struct sigqueue *head, *tail;//信号队列,记录接收到的信号及相关信息
sigset_t signal; //未决信号集
};
struct sigqueue{
struct sigqueue *next; //指向下一个信号队列
siginfo_t info; //记录信号携带的信息
}
在进程恢复运行时,会判断有没有未决信号。如果有,会先删除未决信号链,处理相应的信号。对于非实时信号,因为只会保存一个信号队列,所以会同时清除未决信号集相应位的标记。对于实时信号,因为可能保存几个信号队列,等都处理完了,再清除未决信号集相应位的标记。
信号的安装:
Void signalHandler(int signo); signal(signo, signalHandler);
不能携带信息,主要处理非实时信号。
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
参数1:信号值;参数二:信号处理函数,可携带信息;参数三:
struct sigaction {
union{
__sighandler_t _sa_handler;
void (*_sa_sigaction)(int,struct siginfo *, void *);
}_u
sigset_t sa_mask;//屏蔽信号集,
unsigned long sa_flags;// SA_SIGINFO标志位与_sa_sigaction必须同时定义,否则用sa_handler处理。
}
信号发送:
int kill(pid_t pid,int signo);
int sigqueue(pid_t pid, int sig, const union sigval val);
用于与sa_sigaction配合使用,携带信息。只能对单个进程发送,接收进程处于阻塞状态的话,会存放该信号在PCB信号队列中,信息存放在相应的siginfo中。
typedef union sigval {
int sival_int;
void *sival_ptr; //接收进程可访问的地址
}sigval_t;
unsigned int alarm(unsigned int seconds);//seconds秒之后发送SIGALRM信号
int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
设置定时器,定时发送SIGALRM或SIGVTALRM信号
void abort(void); //向进程发送SIGABORT信号
int raise(int signo)// 向进程本身发送信号,参数为即将发送的信号值。
示例代码参考:
http://bbs.csdn.net/topics/330080188
http://www.cnblogs.com/hoys/archive/2012/08/19/2646377.html
Socket
Socket套接字设计用来实现网络中进程间通信,同时也可用于本地进程间通信。利用网络唯一标识IP地址+协议+端口唯一标识一个进程。运用这唯一标识以及TCP(UDP)/IP协议族就可以实现网络间进程的通信。Socket是一个特殊的文件,实现了打开,读写IO,关闭等基本操作。
创建socket
int socket(int domain, int type, int protocol);
参数一:domain为协议域或协议族。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
参数二:type为socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
类型描述:SOCK_DGRAM长度固定的、无连接的不可靠报文传递SOCK_RAM IP协议的数据报接口SOCK_SEQPACKET长度固定、有序、可靠的面向连接报文传递SOCK_STREAM有序、可靠、双向的面向连接字节流
参数三:protocol为协议类型。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。当protocol为0时,会自动选择type类型对应的默认协议。
返回值:返回一个套接字描述符,<0表示创建失败。
Bind socket:
用于将套接字描述符与对应的IP地址、端口、协议进行绑定,以便后续通信。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数一:套接字描述符。
参数二:sockaddr结构,根据协议不一样,结构定义也不相同。
IPV4:
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
ipv6对应的是:
struct sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* port number */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */
};
struct in6_addr {
unsigned char s6_addr[16]; /* IPv6 address */
};
本地SOCKET:
struct sockaddr_un {
sa_family_t sin6_family; // AF_UNIX AF_LOCAL
unsigned char path[];
};
参数三:地址长度
返回值:返回-1,绑定失败。
服务器端,监听套接字
int listen(int sockfd, int backlog);
第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。
客户端,连接套接字
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。
服务器端,接收来自客户端的请求
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。
注意:accept的第一个参数为服务器的socket描述字,是服务器开始调用socket()函数生成的,称为监听socket描述字;而accept函数返回的是已连接的socket描述字。一个服务器通常通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。
读写操作
- read()/write()
- recv()/send()
- readv()/writev()
- recvmsg()/sendmsg()
- recvfrom()/sendto()
int send(int sockfd, const void *msg, int len, int flags);
int recv(int sockfd, void *buf, int len, unsigned int flags)
int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);
int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int fromlen)
int read(int fd, char *buf, int len)
int write(int fd, char *buf, int len)
关闭套接字
int close(int fd);
close一个TCP socket的缺省行为时把该socket标记为以关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用,也就是说不能再作为read或write的第一个参数。
注意:close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。
TCP三次握手:
四次握手,释放连接
参考http://blog.csdn.net/gladyoucame/article/details/8768731
http://www.cnblogs.com/fuchongjundream/p/3914696.html
字节序转换:
主机字节序:就是我们平常说的大端和小端模式:不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序。引用标准的Big-Endian和Little-Endian的定义如下:
a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
网络字节序:4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。这种传输次序称作大端字节序。由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序,一个字节的数据没有顺序的问题了。所以:在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。
字节序转换函数
htonl: 转换long类型到网络字节序
htons: 转换short类型到网络字节序
ntohl: 转换网络字节序到long类型
ntohs: 转换网络字节序到short类型
inet_addr: 将字符串格式IP转换到网络字节序
inet_ntoa: 将网络字节序格式IP转换到字符串
举例:SOCKADDR_IN中的数据格式
SOCKADDR_IN addr;
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(5120)
本地socket
可用UNIX socket实现,也可用INET socket实现,服务器端地址绑定:
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 将INADDR_ANY转换为网络字节序,调用 htonl(long型)或htons(整型)
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
客户端connect地址:
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 本地回路地址是127.0.0.1;
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
UNIX socket代码实现如下:
服务器端代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define UNIX_DOMAIN "/tmp/domain"
#define MAX_CONNECT 1
int main(int argc, char **argv)
{
//variables
int serverFd;
int cltFd;
int ret = 0;
struct sockaddr_un srvAddr;
struct sockaddr_un cltAddr;
int connectFd[MAX_CONNECT] = {0};
char buf[1024];
//create socket
serverFd = socket(AF_UNIX, SOCK_STREAM, 0);
if (serverFd < 0)
{
perror("create socket failed");
return -1;
}
//bind socket
srvAddr.sun_family = AF_UNIX;
strncpy(srvAddr.sun_path, UNIX_DOMAIN, sizeof(UNIX_DOMAIN));
unlink(UNIX_DOMAIN);
ret = bind(serverFd, (struct sockaddr*)&srvAddr, sizeof(srvAddr));
if (ret == -1)
{
perror("bind socket failed");
close(serverFd);
return -1;
}
//listen socket
ret = listen(serverFd, MAX_CONNECT);
if (ret == -1)
{
perror("listen failed");
close(serverFd);
unlink(UNIX_DOMAIN);
return -1;
}
//accept socket
cltFd = accept(serverFd, (struct sockaddr*)&cltAddr, (socklen_t*)&(sizeof(cltAddr)));
if (ret < 0)
{
perror("accept failed");
close(serverFd);
unlink(UNIX_DOMAIN);
return -1;
}
//read/write
do
{
memset(buf, 0, sizeof(buf));
int num = read(cltFd, buf, sizeof(buf));
printf("message from client(%d):%s\n", buf);
} while (strcmp(buf, "quit") != 0);
//close socket
close(cltFd);
close(serverFd);
unlink(UNIX_DOMAIN);
return 0;
}
客户端代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define UNIX_DOMAIN "/tmp/domain"
int main(int argc, char **argv)
{
//variables
int serverFd;
int cltFd;
int ret = 0;
struct sockaddr_un srvAddr;
struct sockaddr_un cltAddr;
char buf[1024];
//create socket
cltFd = socket(AF_UNIX, SOCK_STREAM, 0);
if (cltFd < 0)
{
perror("create socket failed");
return -1;
}
//connect
srvAddr.sun_family = AF_UNIX;
strncpy(srvAddr.sun_path, UNIX_DOMAIN, sizeof(UNIX_DOMAIN));
ret = connect(cltFd, (struct sockaddr *)&srvAddr, sizeof(srvAddr));
if (cltFd < 0)
{
perror("create socket failed");
close(cltFd);
unlink(UNIX_DOMAIN);
return -1;
}
//read/write
do
{
memset(buf, 0, sizeof(buf));
printf("input send message(max len 1024):\n");
scanf("%s", buf);
int num = write(cltFd, buf, sizeof(buf));
printf("message from client(%d):%s\n", buf);
} while (strcmp(buf, "quit") != 0);
//close socket
close(cltFd);
unlink(UNIX_DOMAIN);
return 0;
}
网络IP层socket
区别在于域类型不同,且绑定的是sockaddr_in结构,可定义端口/地址
服务器端
#include<sys/socket.h>
#include <unistd.h>// for close function
#include <string.h> // for bzero function
#include<stdio.h>
#include<sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<netinet/in.h>
#include <stdlib.h>
#define SERV_PORT 5555
#define SERV_IP "xxx.xxx.xxx.xxx"//mx27 board ip
#define BACKLOG 10 //the counts of connect can keep in wait queen
#define MAXBUFSIZE 200
char buf[MAXBUFSIZE]; //receive buf
char str_to_send[200] ="important notice:to cerebrate China log on moon successful on 12nd,Jan,2010. everyone has a day free from work!/n";
int main(int argc, char **argv)
{
int sockfd,sockfd_client;
socklen_t sin_size; // used in accept(),but i don't know what it means
printf("#####################################################/n");
printf("socket receive text by pafone 30th,April,2009/n");
printf("server ip:%s port:%d /n",SERV_IP,SERV_PORT);
printf("#####################################################/n");
struct sockaddr_in my_addr;//local ip info
struct sockaddr_in serv_addr,client_sockaddr; //server ip info
int serverport;
if(argc == 2)
{
serverport = atoi(argv[1]);
}
else
{
serverport = SERV_PORT;
}
if(-1 == (sockfd = socket(AF_INET,SOCK_STREAM,0)) )
{
perror("error in create socket/n");
exit(0);
}
//set the sockaddr_in struct
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(serverport);//server listening port
serv_addr.sin_addr.s_addr = INADDR_ANY;//here is the specia in listening tcp connect
bzero(&serv_addr.sin_zero,8);
//bind , the ip and port information is aready in the sockaddr
if(-1 == bind(sockfd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr)))
{
perror("bind error/n");
exit(0);
}
printf("bind seccessful/n");
if(-1 == listen(sockfd,BACKLOG))
{
perror("lisenning");
exit(1);
}
printf("the server is listenning.../n");
//accept
printf("before accept:sockfd_client is %d/n",sockfd_client);
if(-1 == (sockfd_client = accept(sockfd,(structsockaddr*)&client_sockaddr,&sin_size)))
{
perror("accept");
exit(1);
}
printf("accept connect./n");
int recvbytes;//the number of bytes receive from socket
// char buffer[200];
// printf("sockfd_client is %d/n",sockfd_client);
// recvbytes = recv(sockfd_client,buffer,200,0);
if(-1 == (recvbytes = recv(sockfd_client,buf,MAXBUFSIZE,0)))//changed here
if(-1 == recvbytes)
{
perror("receive");
exit(1);
}
printf("%dbytes receive from connect:%s/n",recvbytes,buf);
close(sockfd);
close(sockfd_client);
}
客户端代码:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#define SERVPORT 5555
#define DEST_IP "192.168.1.158"
int main(int argc, char **argv)
{
int sockfd,sock_dt;
printf("#####################################################\n");
printf("socket test by pafone 19th,April,2009\n");
printf("#####################################################\n");
struct sockaddr_in my_addr;//local ip info
struct sockaddr_in dest_addr; //destnation ip info
if(argc != 3)
{
printf("useage:socket_client ipaddress port\n eg:socket_client \/par 192.168.1.158 5555");
return -1;
}
int destport = atoi(argv[2]);
if(-1 == (sockfd = socket(AF_INET,SOCK_STREAM,0)) )
{
perror("error in create socket\n");
exit(0);
}
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(destport);
dest_addr.sin_addr.s_addr = inet_addr(argv[1]);
// bzero(&dest_addr.sin_zero,0,8);
memset(&dest_addr.sin_zero,0,8);
//connect
if(-1 == connect(sockfd,(struct sockaddr*)&dest_addr,sizeof(struct sockaddr)))
{
perror("connect error\n");
exit(0);
}
int n_send_len;
n_send_len = send(sockfd,"-f00k you.\n-why?\n-how\n",strlen("-fuck you.\n-why?\n-how\n"),0);
printf("%d bytes sent\n",n_send_len);
n_send_len = send(sockfd,"-**** you.\n-why?\n-how\n",strlen("-fuck you.\n-why?\n-how\n"),0);
printf("%d bytes sent\n",n_send_len);
while(1);
close(sockfd);
}
链路层 raw socket
#include <stdlib.h>
#include <stdio.h>
//#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <errno.h>
typedef struct eth_hdr
{
unsigned char dstMac[6];
unsigned char srcMac[6];
unsigned short proType;//IPV4, IPV6, ARP, IPX
}ETH_HEADER;
typedef struct ip_hdr //定义IP首部
{
unsigned char h_verlen; //4位首部长度,4位IP版本号
unsigned char tos; //8位服务类型TOS
unsigned short total_len; //16位总长度(字节)
unsigned short ident; //16位标识
unsigned short frag_and_flags; //3位标志位
unsigned char ttl; //8位生存时间 TTL
unsigned char proto; //8位协议 (TCP, UDP 或其他)
unsigned short checksum; //16位IP首部校验和
unsigned int sourceIP; //32位源IP地址
unsigned int destIP; //32位目的IP地址
}IPHEADER;
typedef struct tsd_hdr //定义TCP伪首部
{
unsigned long saddr; //源地址
unsigned long daddr; //目的地址
char mbz;
char ptcl; //协议类型
unsigned short tcpl; //TCP长度
}PSDHEADER;//仅用于校验
typedef struct _tcphdr //定义TCP首部
{
unsigned short th_sport; //16位源端口
unsigned short th_dport; //16位目的端口
unsigned int th_seq; //32位序列号
unsigned int th_ack; //32位确认号
unsigned char th_lenres; //4位首部长度/6位保留字
unsigned char th_flag; //6位标志位
unsigned short th_win; //16位窗口大小
unsigned short th_sum; //16位校验和
unsigned short th_urp; //16位紧急数据偏移量
}TCP_HEADER;
typedef struct udp_hdr
{
unsigned short srcPort;
unsigned short dstPort;
unsigned short dataLength;
unsigned short checkSum;
}UDP_HEADER;
unsigned short checksum(unsigned short *buffer, int size)
{
unsigned long cksum=0;
while(size > 1)
{
cksum+=*buffer++;
size -=sizeof(unsigned short);
}
if(size)
{
cksum += *(unsigned char*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (unsigned short)(~cksum);
}
#define BUFFER_MAX 2048
int main(int argc, char* argv[], ...)
{
int sock = 0;
int nread;
int proto;
char buffer[BUFFER_MAX];
char *ethhead, *ipHead, *tcpHead, *udpHead, *icmpHead, *p;
sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
if (sock < 0)
{
printf("Socket Setup Error! %d\n", errno);
return -1;
}
while(1)
{
nread = recvfrom(sock, buffer, 2048, 0, NULL, NULL);
/*
14 6(dest)+6(source)+2(type or length)
+
20 ip header
+
8 icmp,tcp or udp header
= 42
*/
if(nread < 42)
{
fprintf(stdout, "Incomplete header, packet corrupt\n");
continue;
}
ethhead = buffer;
p = ethhead;
int n = 0XFF;
printf("MAC: %.2X:%02X:%02X:%02X:%02X:%02X==>"
"%.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n",
p[6]&n, p[7]&n, p[8]&n, p[9]&n, p[10]&n, p[11]&n,
p[0]&n, p[1]&n, p[2]&n,p[3]&n, p[4]&n, p[5]&n);
ipHead = ethhead + 14;
p = ipHead + 12;
printf("IP: %d.%d.%d.%d => %d.%d.%d.%d\n",
p[0]&0XFF, p[1]&0XFF, p[2]&0XFF, p[3]&0XFF,
p[4]&0XFF, p[5]&0XFF, p[6]&0XFF, p[7]&0XFF);
proto = (ipHead + 9)[0];
p = ipHead + 20;
printf("Protocol: ");
switch(proto)
{
case IPPROTO_ICMP: printf("ICMP\n");break;
case IPPROTO_IGMP: printf("IGMP\n");break;
case IPPROTO_IPIP: printf("IPIP\n");break;
case IPPROTO_TCP:
case IPPROTO_UDP:
printf("%s,", proto == IPPROTO_TCP ? "TCP": "UDP");
printf("source port: %u,",(p[0]<<8)&0XFF00 | p[1]&0XFF);
printf("dest port: %u\n", (p[2]<<8)&0XFF00 | p[3]&0XFF);
break;
case IPPROTO_RAW :
printf("RAW\n");break;
default:
printf("Unkown, please query in include/linux/in.h/n");
}
printf("\n\n");
}
}
也可参考:http://www.cnblogs.com/uvsjoh/archive/2012/12/31/2840883.html
- 优缺点总结
无名管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用;有名管道也是半双工,但是允许无亲缘关系进程间通信。但是由于其长期存在于系统之中,使用不当容易出错.所以普通用户一般不建议使用。
信号机制能提供一种软中断,也可传递信息,但不适合信息量大
消息队列,由于拷贝信息需要消耗CPU时间,所以不适合信息量大和频繁交换的通信。