进程间通信

进程间通信的方式有信号量、共享内存、管道、消息队列、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);

  1. struct msg_st  
  2. {  
  3.     long int msg_type;  
  4.     char text[BUFSIZ];  
  5. };
  6. struct msg_st data; long int msgtype = 0;
  7. msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0) 

发送消息

int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);

char buffer[BUFSIZ];

  1. fgets(buffer, BUFSIZ, stdin);  
  2. data.msg_type = 1;
  3. strcpy(data.text, buffer);  
  4. //向队列发送数据  
  5. 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);

设置定时器,定时发送SIGALRMSIGVTALRM信号

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时间,所以不适合信息量大和频繁交换的通信。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值