socket知識
有了IP地址,socket可知道是與哪一臺主機的哪一個進程通信
有了端口號,就知道是這個進程的哪一個套接字進行傳輸
應用進程使用描述符與它的套接字進行通信,也就是說一個進程創建一個套接字時就會返回一個套接字描述符
socket的地址信息最重要
已定義了結構sockaddr_in
:,使用TCP/IP協議族的網絡應用程序聲明端點地址變量時,使用結構sockaddr_in
struct sockaddr_in
{u_char sin_len; //地址長度u_char sin_family; //地址族 TCP/IP的地址是AF_INETu_short sin_port; //端口號struct in_addr sin_addr; //IP地址char sin_zero[8]; //未用
}
socket api(WinSock)
windows環境下,先使用WSAStartup
初始化Windows Sockets API
,然后應用程序執行任務,最后執行WSACleanup
釋放所使用的Windows Sockets DLL
占用的系統資源,接觸與socket庫的綁定。
WSAStartup
int WSAStartup(WORD wVersionRequested,LPWSADATA IpWSAData);
使用Socket的應用程序在使用Socket之前必須首先調用WSAStartup函數
兩個參數:
-
第一個參數指明程序請求使用WinSock版本,高位字節指明副版本、低位字節指明主版本
- 0x102表示2.1版本
-
第二個參數返回實際的WinSock的版本信息
- 指向WSADATA結構的指針
例:使用2.1版本WinSock的程序代碼段
wVersionRequested = MAKEWORD(2,1);
err = WSAStartup(wVersionRequested,&wsaData);
socket
該函數創建套接字
sd = socket(protofamily,type,proto);
-
創建套接字
-
操作系統返回套接字描述符(sd)
-
第一個參數(協議族):protofamily = PF_INET (TCP/IP)
-
第二個參數(套接字類型):
type = SOCK_STREAM,SOCK_DGRAM or SOCK_RAW(TCP/IP)
-
第三個參數(協議號):0為默認
例:創建一個流套接字的代碼段
struct protoent *p;
p = getprotobyname("tcp");
SOCKET sd = socket(PF_INET,SOCK_STREAM,p->p_proto);
不同類型的socket用于應用層與下層不同協議進行溝通。需要注意的是原始套接字SOCK_RAW需要擁有比較高的權限
TCP提供的服務特點:
可靠、面向連接、字節流傳輸、點對點
UDP提供的服務特點:
不可靠、無連接、數據報傳輸
Closesocket
int closesocket(SOCKET sd);
-
關閉一個描述符為sd的套接字
-
如果多個進程共享一個套接字,調用
closesocket
,將套接字引用計數減1,減至0才關閉 -
一個進程中的多線程對一個套接字的使用無計數
- 如果進程中的一個線程調用
closesocket
將一個套接字關閉,該進程中的其他線程也將不能訪問該套接字
- 如果進程中的一個線程調用
-
返回值:0成功,SOCKET_ERROR不成功
bind
套接字創建的時候可能并沒有地址 ,可以調用bind函數產生一個地址,或者說是用來綁定套接字的本地端點地址
int bind(sd,localaddr,addrlen);
端點地址其實就是IP地址 + 端口號
-
參數
- 套接字描述符 sd
- 端點地址 localaddr,結構為sockaddr_in
- 地址長度
-
客戶程序一般不必顯式調用bind函數,因為操作系統會幫助我們設置客戶端的端點地址
-
對于服務器端需要調用,用來指定熟知端口號以及IP地址。如果服務器主機有多個網卡,產生多個ip地址,需要使用地址通配符,INADDR_ANY。表示在服務器運行的主機上任何一個可用ip地址都是可以用來傳輸的
listen
int listen(sd,queuesize);
-
置服務器端的流套接字處于監聽狀態
- 僅服務器端調用
- 僅用于面向連接的流套接字
-
設置連接請求隊列(緩存)大小
-
返回值: 成功為0,失敗為SOCKET_ERROR
connect
connect(sd,saddr,saddrlen);
- 客戶程序調用connect函數來使客戶套接字sd與特定計算機的特定端口saddr的套接字服務進行連接
- 僅僅用于客戶端
- 可用于TCP客戶端也可以用于UDP客戶端
- TCP客戶端:建立了TCP連接
- UDP客戶端:只指定服務器端點地址
accept
newsock = accept(sd,caddr,caddrlen);
-
服務程序調用accept函數從處于監聽狀態的流套接字sd的客戶連接請求隊列中取出排在最前的一個客戶請求,并且創建一個新的套接字來與客戶套接字創建連接通道
- 僅僅用于TCP套接字
- 僅僅用于服務器
-
利用新創建的套接字newsock與客戶通信
為什么要這樣做呢?因為TCP是點對點的,說明只能連接客戶端和服務器的兩個套接字。如果不這么做,就會導致TCP服務器在同一時刻只能為某一個客戶提供服務,不能實現并發了。
send,sendto
send(sd,*buf,len,flags);
sendto(sd,*buf,len,flags,destaddr,addrlen);
- send函數用于TCP套接字(客戶與服務器)或調用了connect函數的UDP客戶端套接字
- sendto函數用于UDP服務器端套接字與為調用connect函數的UDP客戶端套接字
recv,recvfrom
與上面的send、sendto對應
recv(sd,*buffer,len,flags);
recvfrom(sd,*buf,len,flags,senderaddr,saddrlen);
- recv函數從TCP連接的另一端接收數據,或者從調用了connect函數的UDP客戶端套接字接收服務器發來的數據
- recvfrom函數用于從UDP服務器套接字與未調用connect函數的UDP客戶端套接字接收對端數據
setsockopt,getsockopt
int setsockopt(int sd,int level,int optname,*optval,int optlen);
int getsockopt(int sd,int level,int optname,*optval,int socklen_t* optlen);
- setsockopt()函數用來設置套接字sd的選項參數
- getsockopt()函數用來獲取任意類型、人影狀態的套接口的選項當前值,并吧結果存入optval