Linux教程網
進程通信的概念最初來源於單機系統,由於每個進程都在各自的地址范圍內運行,為了保證兩個相互通信的進程之間既不互相干擾,又協調一致的工作,操作系統為進程通信提供了相應設施,如UNIX BSD中的管道(pipe),有名管道(named pipe)和軟中斷信號(singal),UNIX system V的消息(message)、共享存儲區(shared memory)和信號量(semaphore)等,但都局限於用在本機進程之間通信。網間進程通信要解決的是不同主機進程間的通信問題(可把同機進程通信看作其中的特例)。為此,首先要解決的是網間進程標識問題。同一主機上,不同進程可以用進程號(pid)唯一標識。但在網絡環境下,各主機獨立分配的進程號不能唯一標識該進程。例如主機A賦予某進程號5,在B主機也可以存在5號進程,因此5號進程這句話就沒有意義了。其次,操作系統支持的網絡協議眾多,不同協議的工作方式不同,地址格式也不同。因此,網間進程通信還要解決多重協議的識別問題。為了解決上述問題,TCP/IP協議引入了下列幾個概念。
端口
網絡中可以被命名和尋址的通信端口是操作系統可分配的一種資源。按照OSI七層協議的描述,傳輸層與網絡層最大的區別是傳輸層提供進程通信能力。從這個意義上講,網絡通信的最終地址就不僅是主機地址了,還包括可以描述進程的某種標識符。為此TCP/IP協議提出了協議端口的概念,用於標識通信的進程。
端口是一種抽象的軟件結構,包括一些數據結構和I/O緩沖區。應用程序即進程通過系統調用與某端口建立連接(binding)後,傳輸層傳給該端口的數據都被相應的進程所接收,相應進程發給傳輸層的數據都從該端口輸出。在TCP/IP協議的實現中,端口操作類似於一般的I/O操作,進程獲取一個端口,相當於獲取本地唯一的I/O文件,可以用一般的讀寫原語訪問。
類似於文件描述符,每個端口都擁有一個叫端口號的整數描述符,以區別不同端口。由於TCP/IP傳輸層的兩個協議TCP和UDP是兩個完全獨立的軟件模塊,因此各自的端口號也相互獨立。如TCP有一個255號端口,UDP也可以有一個255號端口,兩者並不沖突。
端口號的分配是一個重要問題,有兩種基本分配方式:第一種叫全局分配這是一種集中分配方式,由一個公認的中央機構根據用戶需要盡行統一分配,並將結果公布於眾,第二種是本地分配,又稱動態連接,即進程需要訪問傳輸層服務時,向本地操作系統提出申請,操作系統返回本地唯一的端口號,進程再通過合適的系統調用,將自己和該端口連接起來(綁定)。TCP/IP端口號的分配綜合了兩種方式。TCP/IP將端口號分為兩部分,少量的作為保留端口,以全局方式分配給服務進程。因此,每一個標准服務器都擁有一個全局公認的端口叫周知口,即使在不同的機器上,其端口號也相同。剩余的為自由端口,以本地方式進行分配。TCP和UDP規定,小於256的端口才能作為保留端口。
地址
網絡通信中的兩個進程分別在兩個不同的機器上。在互連網絡中,兩台機器可以位於不同的網絡,這些網絡通過網際互連設備(網關,網橋,路由器)連接。因此需要三級尋址。
1。某一主機與多個網絡相連,必須指定一特定網絡地址;
2。網絡上美一台主機應有其唯一的地址;
3。美一主機上的每一進程應有在該主機上的唯一標識。
主機地址就是IP啦,不必多說。進程唯一標識符是十六位整數端口號。
網絡字節順序
不同的計算機存放多字節值的順序不同,有的機器在起始地址存放低位字節,有的則相反。為保證數據的正確性,在網絡協議中需指定網絡字節順序。TCP/IP協議使用16位整數和32位整數的高價先存格式,他們均含在協議的頭文件中。
連接
兩個進程間的通信鏈路稱為連接。連接在內部表現為一些緩沖區和一組協議機制,在外部表現出比無連接高的可靠性。
半相關
綜上所述,網絡中用一個三元組可以在全局中唯一標是一個進程:(協議,本機地址,本地端口號)這樣一個三元組,叫做一個半相關,他指定連接的每半部分。
全相關
一個完整的網間進程通信需要有兩個進程組成,並且只能使用同一種高層協議。也就是說TCP和UDP沒法通信。因此一個完整的網間進程通信需要一個五元組來標識:
(協議,本機地址,本地端口號,遠地地址,遠地端口號)這樣一個五元組叫做一個全相關。
小馬 回復於:2003-01-15 09:40:43
有沒有樣板程序?
急
謝謝了
小馬 回復於:2003-01-15 10:05:15
有沒有樣板程序?
哪位能應一下!
lixshn 回復於:2003-01-15 12:16:31
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "../incl/hbjm.h"
#define READWRITE_TIMEOUT 15
#define PKG_LEN 100
EXEC SQL include sqlca;
EXEC SQL include sqlda;
main()
{
struct servent *svrent;
struct sockaddr_in addr_in;
int svrsock,newsocket;
int childid;
int m_pkg=0;
char strTime[10];
char date[9];
int val=1;
set_resident(); // 進程成為常駐進程
init:
signal( SIGCHLD, sig_chld );
memset(&addr_in,0,sizeof(struct sockaddr_in));
addr_in.sin_family=AF_INET;
addr_in.sin_addr.s_addr=INADDR_ANY;
addr_in.sin_port=htons(8003);
svrsock=socket(AF_INET,SOCK_STREAM,0);
if ( svrsock<0 ) {
printf("socket failed!");
exit(-1);
}
if ( setsockopt(svrsock,SOL_SOCKET,SO_REUSEPORT,&val,sizeof(val)) )
{
printf("setsockopt failed! errno=(%d)",errno);
exit(-1);
}
if( bind(svrsock,(struct sockaddr *)&addr_in,sizeof(addr_in)) ) {
close(svrsock);
printf("bind failed!");
exit(-1);
}
if ( listen(svrsock,20) ) {
close(svrsock);
printf("listen failed !");
exit(-1);
}
while(1)
{
if( ( newsocket=accept(svrsock,0,0) ) < 0 )
{
if( errno == EINTR )
continue;
else
{
printf("accept failed!");
close(svrsock);
goto init;
}
}
if( ( childid = fork() ) == 0 )
{
/* 收交易包 */
signal(SIGALRM,r_alarm);
alarm(READWRITE_TIMEOUT);
if( open_database() )
{
close(newsocket);
return;
}
if( (m_pkg= read( newsocket, r_buf, PKG_LEN )) <20 )
{
printf("read pkg failed!\n");
close(newsocket);
return;
}
do your work;
if ( write( socket, snd_buf,strlen(snd_buf) ) < strlen(snd_buf) )
{
printf("socket write net pgklen error!\n" );
close(newsocket);
return;
}
}
close(newsocket);
服務端的簡單的sock通訊程序,可以看看!
Copyright ©
Linux教程網 All Rights Reserved