信號量是一個計數器,用於多進程對共享數據的訪問,信號量的意圖在於進程間同步。
爲了得到共享資源,進程須要執行下列操做: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文件:
程序運行的結果以下圖:
參考文章: