信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。
为了得到共享资源,进程须要执行下列操做:html
为了正确地实现信号量,信号量值的测试及减1操做应当是原子操做。为此,信号量一般是在内核中实现的。Linux环境中,有三种类型:Posix(可移植性操做系统接口)有名信号量(使用Posix IPC名字标识)、Posix基于内存的信号量(存放在共享内存区中)、System V信号量(在内核中维护)。这三种信号量均可用于进程间或线程间的同步。linux
Posix有名信号量服务器
Posix基于内存的信号量网络
System V信号量多线程
操做也被成为PV原语(P来源于荷兰语proberen"测试",V来源于荷兰语verhogen"增长",P表示经过的意思,V表示释放的意思),而普通整型变量则能够在任何语句块中被访问;socket
互斥量用于线程的互斥,信号量用于线程的同步。这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。tcp
互斥:是指某一资源同时只容许一个访问者对其进行访问,具备惟一性和排它性。但互斥没法限制访问者对资源的访问顺序,即访问是无序的。函数
同步:是指在互斥的基础上(大多数状况),经过其它机制实现访问者对资源的有序访问。测试
在大多数状况下,同步已经实现了互斥,特别是全部写入资源的状况一定是互斥的。少数状况是指能够容许多个访问者同时访问资源ui
互斥量值只能为0/1,信号量值能够为非负整数。
也就是说,一个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量能够实现多个同类资源的多线程互斥和同步。当信号量为单值信号量是,也能够完成一个资源的互斥访问。
互斥量的加锁和解锁必须由同一线程分别对应使用,信号量能够由一个线程释放,另外一个线程获得。
套接字是一种通讯机制,凭借这种机制,客户/服务器(即要进行通讯的进程)系统的开发工做既能够在本地单机上进行,也能够跨网络进行。也就是说它可让不在同一台计算机但经过网络链接计算机上的进程进行通讯。
套接字是支持TCP/IP的网络通讯的基本操做单元,能够看作是不一样主机之间的进程进行双向通讯的端点,简单的说就是通讯的两方的一种约定,用套接字中的相关函数来完成通讯过程。
套接字的特性由3个属性肯定,它们分别是:域、端口号、协议类型。
它指定套接字通讯中使用的网络介质,最多见的套接字域有两种:
AF_UNIX,表示UNIX文件系统,它就是文件输入/输出,而它的地址就是文件名。
每个基于TCP/IP网络通信的程序(进程)都被赋予了惟一的端口和端口号,端口是一个信息缓冲区,用于保留Socket中的输入/输出信息,端口号是一个16位无符号整数,范围是0-65535,以区别主机上的每个程序(端口号就像房屋中的房间号),低于256的端口号保留给标准应用程序,好比pop3的端口号就是110,每个套接字都组合进了IP地址、端口,这样造成的总体就能够区别每个套接字。
原始套接字
原始套接字容许对较低层次的协议直接访问,好比IP、 ICMP协议,它经常使用于检验新的协议实现,或者访问现有服务中配置的新设备,由于RAW SOCKET能够自如地控制Windows下的多种协议,可以对网络底层的传输机制进行控制,因此能够应用原始套接字来操纵网络层和传输层应用。好比,咱们能够经过RAW SOCKET来接收发向本机的ICMP、IGMP协议包,或者接收TCP/IP栈不可以处理的IP包,也能够用来发送一些自定包头或自定协议的IP包。网络监听技术很大程度上依赖于SOCKET_RAW。
原始套接字与标准套接字的区别
原始套接字能够读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。所以,若是要访问其余协议发送数据必须使用原始套接字。
eg.
服务端代码
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> //socket listen bind #include <sys/socket.h>//socket listen bind #include <unistd.h>//unlink #include <sys/un.h>//struct sockaddr_un int main() { /* delete the socket file */ unlink("server_socket"); /* create a socket */ int server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un server_addr; server_addr.sun_family = AF_UNIX; strcpy(server_addr.sun_path, "server_socket"); /* bind with the local file */ bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); /* listen */ listen(server_sockfd, 5); char ch; int client_sockfd; struct sockaddr_un client_addr; socklen_t len = sizeof(client_addr); while(1) { printf("server waiting:\n"); /* accept a connection */ client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_addr, &len); /* exchange data */ read(client_sockfd, &ch, 1); printf("get char from client: %c\n", ch); ++ch; write(client_sockfd, &ch, 1); /* close the socket */ close(client_sockfd); } return 0; }
客户端代码
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> //socket listen bind #include <sys/socket.h>//socket listen bind #include <unistd.h>//unlink #include <sys/un.h>//struct sockaddr_un int main() { /* create a socket */ int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un address; address.sun_family = AF_UNIX; strcpy(address.sun_path, "server_socket"); /* connect to the server */ int result = connect(sockfd, (struct sockaddr *)&address, sizeof(address)); if(result == -1) { perror("connect failed: "); exit(1); } /* exchange data */ char ch = 'A'; write(sockfd, &ch, 1); read(sockfd, &ch, 1); printf("get char from server: %c\n", ch); /* close the socket */ close(sockfd); return 0; }
若是咱们首先运行tcp_client,会提示没有这个文件:
由于咱们是以AF_UNIX方式进行通讯的,这种方式是经过文件来将服务器和客户端链接起来的,所以咱们应该先运行tcp_server,建立这个文件,默认状况下,这个文件会建立在当前目录下,而且第一个s表示它是一个socket文件:
程序运行的结果以下图:
参考文章: