socket-几点
1.
tcp連接,服務(wù)器端的accept返回的套接字怎么和客戶端對(duì)應(yīng)的套接字通信?
tcp server端進(jìn)行的動(dòng)作有
//創(chuàng)建STREAM socket
int server_sockfd;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
//想要監(jiān)視的地址及端口
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
server_address.sin_port = 9734;
//綁定
? ? bind(server_sockfd, (struct sockaddr *)&server_address, sizeof(server_address));
//創(chuàng)建隊(duì)列,此處可以允許兩個(gè)客戶同時(shí)連接
? ? listen(server_sockfd,2);
//阻塞在此處,直到有客戶請(qǐng)求連接
? ? int ?client_sockfd;
? ? struct sockaddr_in client_address;
? ? client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &sizeof(client_address));
//阻塞在此處,直到該客戶有寫數(shù)據(jù)到client_sockfd?
? ? ? ? read(client_sockfd, &ch, 1);
? ? ? ? ch++;
? ? ? ? write(client_sockfd, &ch, 1);
tcp client端進(jìn)行的動(dòng)作有
//創(chuàng)建socket
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
//想要連接的服務(wù)器地址和端口
?struct sockaddr_in address;
?address.sin_family = AF_INET;
?address.sin_addr.s_addr = inet_addr("127.0.0.1");
?address.sin_port = 9734;
//連接
connect(sockfd, (struct sockaddr *)&address, len);
//寫數(shù)據(jù)
write(sockfd, &ch, 1);
read(sockfd, &ch, 1);
當(dāng)服務(wù)器在while中循環(huán)監(jiān)聽(accept)時(shí),每有一個(gè)客戶端連接,服務(wù)器端的accept都會(huì)有建立一個(gè)新的套接字描述符(即一個(gè)int數(shù)字)來代表當(dāng)前的這個(gè)連接.如下
The file descriptor returned by accept is a socket descriptor that is connected to the client that called connect. This new socket descriptor has the same socket type and address family as the original socket (sockfd). The original socket passed to accept is not associated with the connection, but instead remains available to receive additional connect requests.--apue2-16.4
假設(shè)server已經(jīng)在192.168.1.110上運(yùn)行起來,
在192.168.1.111上啟動(dòng)client A,假設(shè)client A創(chuàng)建的套接字描述符是10,
當(dāng)client A進(jìn)程執(zhí)行connect操作時(shí),Server會(huì)accept,并返回一個(gè)新的套接字描述符比如5表示這個(gè)連接。那么5究竟怎么唯一表示這個(gè)連接呢?
當(dāng)client A進(jìn)程執(zhí)行write(sockfd, &ch, 1)時(shí),其發(fā)出的tcp包首部元素中,源端口號(hào)是12345(其實(shí)沒有指定,os任意選擇一個(gè)未使用的tcp端口號(hào)),目的端口號(hào)是9734。
當(dāng)server進(jìn)程執(zhí)行write(client_sockfd, &ch, 1),其發(fā)出的tcp包首部中,源端口號(hào)是9734(必須的,服務(wù)器已經(jīng)綁定這個(gè)端口,其寫數(shù)據(jù)時(shí)會(huì)將9734塞進(jìn)tcp包首部的源端口號(hào)域中),目的端口號(hào)是123456
假設(shè)客戶端又啟動(dòng)一個(gè)進(jìn)程Client B,假設(shè)Client B創(chuàng)建的套接字描述符是11(與Client A創(chuàng)建的不同,因?yàn)樘捉幼置枋龇募枋龇粯邮侨中缘?。假設(shè)Server進(jìn)程為相應(yīng)Client B的connect而創(chuàng)建的套接字描述符是6。假設(shè)os為Client B的套接字11分配的源地址及端口號(hào)是192.168.1.111:123457。
即
進(jìn)程Server向套接字描述符5寫入數(shù)據(jù)時(shí),tcp包中指明的源地址及端口是192.168.1.110:9734,目的地址及端口是192.168.1.111:123457
客戶端接收到Server 發(fā)來的tcp包時(shí),發(fā)現(xiàn)目的端口號(hào)是123457,對(duì)應(yīng)自己的clientB進(jìn)程里的套接字描述符11,便把數(shù)據(jù)塞進(jìn)clientB進(jìn)程的描述符11。
client B向套接字描述符11寫數(shù)據(jù)時(shí),tcp包中指明的源地址及端口是192.168.1.111;123457,目的地址及端口是192.168.1.110:9734
服務(wù)器接收到Client A發(fā)來的tcp包時(shí),發(fā)現(xiàn)目的端口號(hào)時(shí)9734,對(duì)應(yīng)自己的Server進(jìn)程里的套接字描述符6,便把數(shù)據(jù)塞進(jìn)Server進(jìn)程的描述符5。
這樣Server的描述符6和ClientB的描述符11可以傳輸數(shù)據(jù)了。
綜上,一個(gè)既定的socket描述符確定了源地址及端口,目的地址及端口。
另外,在客戶端如果沒有綁定源地址及端口,則os自動(dòng)選擇一個(gè)默認(rèn)的ip和未使用的端口作為此socket的源地址及端口。如上。可以同服務(wù)器端一樣綁定一個(gè)ip及端口,使用bind。
2.setsockopt的幾個(gè)參數(shù)
keepAlive?=?1; int?keepIdle?=?1; int?keepInterval?=?1; int?keepCount?=?1; setsockopt(pSocket->m_ClientSock,?SOL_SOCKET,?SO_KEEPALIVE,?(void*)&keepAlive,?sizeof(keepAlive));//啟用探測 setsockopt(pSocket->m_ClientSock,?SOL_TCP,TCP_KEEPIDLE,?(void?*)&keepIdle,?sizeof(keepIdle));//單位s,當(dāng)線路出現(xiàn)keepIdle?時(shí)間無數(shù)據(jù)傳輸時(shí),會(huì)發(fā)送探測詢問 setsockopt(pSocket->m_ClientSock,?SOL_TCP,TCP_KEEPINTVL,?(void?*)&keepInterval,?sizeof(keepInterval));//單位s,探測發(fā)送時(shí)間間隔 setsockopt(pSocket->m_ClientSock,SOL_TCP,?TCP_KEEPCNT,?(void?*)&keepCount,?sizeof(keepCount));//單位次,探測循環(huán)次數(shù) 在線程執(zhí)行recv/read等時(shí),如果socket沒有數(shù)據(jù),會(huì)阻塞;當(dāng)阻塞時(shí)間過keepIdle后,自動(dòng)啟動(dòng)探測,此時(shí)
如果網(wǎng)線掉落或線路出錯(cuò),則會(huì)返回-1,置錯(cuò)誤號(hào)110。
如果正常,繼續(xù)阻塞。
tcp連接,服務(wù)器端的accept返回的套接字怎么和客戶端對(duì)應(yīng)的套接字通信?
tcp server端進(jìn)行的動(dòng)作有
//創(chuàng)建STREAM socket
int server_sockfd;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
//想要監(jiān)視的地址及端口
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
server_address.sin_port = 9734;
//綁定
? ? bind(server_sockfd, (struct sockaddr *)&server_address, sizeof(server_address));
//創(chuàng)建隊(duì)列,此處可以允許兩個(gè)客戶同時(shí)連接
? ? listen(server_sockfd,2);
//阻塞在此處,直到有客戶請(qǐng)求連接
? ? int ?client_sockfd;
? ? struct sockaddr_in client_address;
? ? client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &sizeof(client_address));
//阻塞在此處,直到該客戶有寫數(shù)據(jù)到client_sockfd?
? ? ? ? read(client_sockfd, &ch, 1);
? ? ? ? ch++;
? ? ? ? write(client_sockfd, &ch, 1);
tcp client端進(jìn)行的動(dòng)作有
//創(chuàng)建socket
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
//想要連接的服務(wù)器地址和端口
?struct sockaddr_in address;
?address.sin_family = AF_INET;
?address.sin_addr.s_addr = inet_addr("127.0.0.1");
?address.sin_port = 9734;
//連接
connect(sockfd, (struct sockaddr *)&address, len);
//寫數(shù)據(jù)
write(sockfd, &ch, 1);
read(sockfd, &ch, 1);
當(dāng)服務(wù)器在while中循環(huán)監(jiān)聽(accept)時(shí),每有一個(gè)客戶端連接,服務(wù)器端的accept都會(huì)有建立一個(gè)新的套接字描述符(即一個(gè)int數(shù)字)來代表當(dāng)前的這個(gè)連接.如下
The file descriptor returned by accept is a socket descriptor that is connected to the client that called connect. This new socket descriptor has the same socket type and address family as the original socket (sockfd). The original socket passed to accept is not associated with the connection, but instead remains available to receive additional connect requests.--apue2-16.4
假設(shè)server已經(jīng)在192.168.1.110上運(yùn)行起來,
在192.168.1.111上啟動(dòng)client A,假設(shè)client A創(chuàng)建的套接字描述符是10,
當(dāng)client A進(jìn)程執(zhí)行connect操作時(shí),Server會(huì)accept,并返回一個(gè)新的套接字描述符比如5表示這個(gè)連接。那么5究竟怎么唯一表示這個(gè)連接呢?
當(dāng)client A進(jìn)程執(zhí)行write(sockfd, &ch, 1)時(shí),其發(fā)出的tcp包首部元素中,源端口號(hào)是12345(其實(shí)沒有指定,os任意選擇一個(gè)未使用的tcp端口號(hào)),目的端口號(hào)是9734。
當(dāng)server進(jìn)程執(zhí)行write(client_sockfd, &ch, 1),其發(fā)出的tcp包首部中,源端口號(hào)是9734(必須的,服務(wù)器已經(jīng)綁定這個(gè)端口,其寫數(shù)據(jù)時(shí)會(huì)將9734塞進(jìn)tcp包首部的源端口號(hào)域中),目的端口號(hào)是123456
即
進(jìn)程Server向套接字描述符5寫入數(shù)據(jù)時(shí),tcp包中指明的源地址及端口是192.168.1.110:9734,目的地址及端口是192.168.1.111:123456
客戶端接收到Server 發(fā)來的tcp包時(shí),發(fā)現(xiàn)目的端口號(hào)是123456,對(duì)應(yīng)自己的clientA進(jìn)程里的套接字描述符10,便把數(shù)據(jù)塞進(jìn)clientA進(jìn)程的描述符10。至于在linux下,數(shù)據(jù)有沒有緩沖,怎么緩沖的,緩沖建立在進(jìn)程空間還是內(nèi)核空間,還不知道。
client A向套接字描述符10寫數(shù)據(jù)時(shí),tcp包中指明的源地址及端口是192.168.1.111;123456,目的地址及端口是192.168.1.110:9734
服務(wù)器接收到Client A發(fā)來的tcp包時(shí),發(fā)現(xiàn)目的端口號(hào)時(shí)9734,對(duì)應(yīng)自己的Server進(jìn)程里的套接字描述符5,便把數(shù)據(jù)塞進(jìn)Server進(jìn)程的描述符5。
假設(shè)客戶端又啟動(dòng)一個(gè)進(jìn)程Client B,假設(shè)Client B創(chuàng)建的套接字描述符是11(與Client A創(chuàng)建的不同,因?yàn)樘捉幼置枋龇募枋龇粯邮侨中缘?。假設(shè)Server進(jìn)程為相應(yīng)Client B的connect而創(chuàng)建的套接字描述符是6。假設(shè)os為Client B的套接字11分配的源地址及端口號(hào)是192.168.1.111:123457。
即
進(jìn)程Server向套接字描述符5寫入數(shù)據(jù)時(shí),tcp包中指明的源地址及端口是192.168.1.110:9734,目的地址及端口是192.168.1.111:123457
客戶端接收到Server 發(fā)來的tcp包時(shí),發(fā)現(xiàn)目的端口號(hào)是123457,對(duì)應(yīng)自己的clientB進(jìn)程里的套接字描述符11,便把數(shù)據(jù)塞進(jìn)clientB進(jìn)程的描述符11。
client B向套接字描述符11寫數(shù)據(jù)時(shí),tcp包中指明的源地址及端口是192.168.1.111;123457,目的地址及端口是192.168.1.110:9734
服務(wù)器接收到Client A發(fā)來的tcp包時(shí),發(fā)現(xiàn)目的端口號(hào)時(shí)9734,對(duì)應(yīng)自己的Server進(jìn)程里的套接字描述符6,便把數(shù)據(jù)塞進(jìn)Server進(jìn)程的描述符5。
這樣Server的描述符6和ClientB的描述符11可以傳輸數(shù)據(jù)了。
綜上,一個(gè)既定的socket描述符確定了源地址及端口,目的地址及端口。
另外,在客戶端如果沒有綁定源地址及端口,則os自動(dòng)選擇一個(gè)默認(rèn)的ip和未使用的端口作為此socket的源地址及端口。如上。可以同服務(wù)器端一樣綁定一個(gè)ip及端口,使用bind。
2.setsockopt的幾個(gè)參數(shù)
keepAlive?=?1; int?keepIdle?=?1; int?keepInterval?=?1; int?keepCount?=?1; setsockopt(pSocket->m_ClientSock,?SOL_SOCKET,?SO_KEEPALIVE,?(void*)&keepAlive,?sizeof(keepAlive));//啟用探測 setsockopt(pSocket->m_ClientSock,?SOL_TCP,TCP_KEEPIDLE,?(void?*)&keepIdle,?sizeof(keepIdle));//單位s,當(dāng)線路出現(xiàn)keepIdle?時(shí)間無數(shù)據(jù)傳輸時(shí),會(huì)發(fā)送探測詢問 setsockopt(pSocket->m_ClientSock,?SOL_TCP,TCP_KEEPINTVL,?(void?*)&keepInterval,?sizeof(keepInterval));//單位s,探測發(fā)送時(shí)間間隔 setsockopt(pSocket->m_ClientSock,SOL_TCP,?TCP_KEEPCNT,?(void?*)&keepCount,?sizeof(keepCount));//單位次,探測循環(huán)次數(shù) 在線程執(zhí)行recv/read等時(shí),如果socket沒有數(shù)據(jù),會(huì)阻塞;當(dāng)阻塞時(shí)間過keepIdle后,自動(dòng)啟動(dòng)探測,此時(shí)
如果網(wǎng)線掉落或線路出錯(cuò),則會(huì)返回-1,置錯(cuò)誤號(hào)110。
如果正常,繼續(xù)阻塞。
轉(zhuǎn)載于:https://www.cnblogs.com/-song/archive/2012/05/30/3331871.html
總結(jié)
- 上一篇: 程序2
- 下一篇: NYOJ-42 一笔画问题