标签:comm cti sys print 因此 信号量 文件系统 管道 建立连接
信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。
为了获得共享资源,进程需要执行下列操作:
为了正确地实现信号量,信号量值的测试及减1操作应当是原子操作。为此,信号量通常是在内核中实现的。Linux环境中,有三种类型:Posix(可移植性操作系统接口)有名信号量(使用Posix IPC名字标识)、Posix基于内存的信号量(存放在共享内存区中)、System V信号量(在内核中维护)。这三种信号量都可用于进程间或线程间的同步。
Posix有名信号量
Posix基于内存的信号量
System V信号量
操作也被成为PV原语(P来源于荷兰语proberen"测试",V来源于荷兰语verhogen"增加",P表示通过的意思,V表示释放的意思),而普通整型变量则可以在任何语句块中被访问;
互斥量用于线程的互斥,信号量用于线程的同步。这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。
互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。
在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源
互斥量值只能为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文件:
程序运行的结果如下图:
参考文章:
标签:comm cti sys print 因此 信号量 文件系统 管道 建立连接
原文地址:https://www.cnblogs.com/joker-wz/p/11013086.html