網路編程基礎瞭解 socket套接字 socket是一種通訊機制,它包含一整套的調用介面和數據結構的定義,他給應用程式提供了使用如TCP/UDP等網路通訊的手段。 linux中的網路編程通過socket介面實現,socket既是一種特殊的IO,提供對應的文件描述符。一個完整的socket都有一個相關 ...
網路編程基礎瞭解
socket套接字
socket是一種通訊機制,它包含一整套的調用介面和數據結構的定義,他給應用程式提供了使用如TCP/UDP等網路通訊的手段。
linux中的網路編程通過socket介面實現,socket既是一種特殊的IO,提供對應的文件描述符。一個完整的socket都有一個相關描述{協議,本地地址,本地埠,遠程地址,遠程埠};每個socket有一個本地唯一Socket,由操作系統分配。
定位某個電腦用IP,定位某個服務用埠。
創建Socket
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
返回:成功返回描述符,出錯返回-1
(詳細可以利用 指令 man socket 查看)
參數解釋
domain
AF_INET IPv4網際網路域
AF_INET6 IPv6網際網路域
AF_UNIX unix域
AF_UNSPEC 未指定
protocol
通常為0,表示按給定的域和套接字類型選擇預設協議。
type(指定採用何種協議)
SOCK_STREAM 採用TCP協議(流式的套接字可以提供可靠的面向連接的通信流)
SOCK_DGRAM 採用UDP協議(數據報套接字)
SOCK_RAW 主要用於新的網路協議實現的測試。
SOCK_SEQPACKET 長度固定、有序、可靠的面向連接報文傳遞
一般採用前兩種方式。。。。。。。
位元組序
位元組序分為大端和小端位元組序
大端位元組序:高位元組在前,低位元組在後
小端位元組序:低位元組在前,高位元組在後
不同體系採用不同的位元組序
網路位元組序:在網路中使用的位元組序稱為網路位元組序,採用大端位元組序。
位元組序的轉換函數
網路傳輸的數據一定要統一順序,所以需要位元組序轉換
uint32_t htonl(uint32_t hostlong); 將一個32位整數由主機(host)位元組序轉換成網路(network)位元組序
uint16_t htons(uint16_t hostshort); 將一個16位整數由主機(host)位元組序轉換成網路(network)位元組序
uint32_t ntohl(uint32_t netlong); 將一個32位整數由網路(network)位元組序轉換成主機(host)位元組序
uint16_t ntohs(uint16_t netshort); 將一個16位整數由網路(network)位元組序轉換成主機(host)位元組序
地址結構
通用地址結構
#include <sys/socket.h>
struct sockaddr{
unsigned short sa_family; //Internet地址族,AF_XXX
char sa_data[14]; //14bytes的協議地址
}
//一般不用
網際網路地址結構
struct in_addr{
in_addr_t s_addr; //ipv4地址
};
struct sockaddr_in{
short int sin_family; //Internet地址族如AF_INET(主機位元組序)
unsigned short int sin port; //埠號,16位值(網路位元組序)將數據轉換之後賦值
struct in_addr sin_addr; //Internet地址,32位ipv4地址(網路位元組序)要將點分十進位轉換成網路位元組序,轉化函數如下
unsigned char sin_zero[8]; //添0(為了格式對其的填充位)
};
點分十進位轉、網路位元組序轉換函數
#include <arp/inet.h>//頭文件
const char *inet_ntop(int domain, const void *restrict addr, char *restrict str, socklen_t size);
返回:成功返回地址字元串指針,出錯返回NULL
功能:網路位元組序轉換成點分十進位 如:127.0.0.1
int inet_pton(int domain, const char *restrict str, void *restrict addr);
返回:成功返回1, 無效格式返回0, 出錯返回-1
功能:點分十進位轉換成網路位元組序
(詳情可利用指令 man inet_pton 查看函數)
參數
domain:Inter 地址族,如AF_INET
addr: Internet地址,32位IPv4地址(網路位元組序)
str:地址字元串(點分十進位)指針
size:地址字元串大小
案例
struct sockaddr_in sockin; //定義一個結構體
char buff[16];
memset(&sockin, 0, sizeof(sockin));
sockin.sin_family = AF_INET; //地址族
sockin.sin_port = htons((short)8888); //埠號,必須是網路位元組序
//填充sin_addr 需要將點分十進位轉換為網路位元組序
if(inet_pton(AF_INET,"127.0.0.1",&sockin.sin_addr.s_addr) <= 0)
{
//進行錯誤處理
}
printf("%s\n",inet_ntop(AF_INET, &sockin.sin_addr.s_addr, buff, sizeof(buff)));
TCP編程模型
客戶端調用序列
調用socket函數創建套接字
調用connect連接伺服器端
調用I/O函數(read/write)與伺服器端通訊
調用close關閉套接字
伺服器端調用序列
調用socket函數創建套接字
調用bind綁定本地地址和埠
調用listen啟動監聽
調用accept從已經連接的隊列中提取刻苦連接
調用I/O函數(read/write)與客戶端通訊
調用close關閉套接字
相關函數
套接字與地址綁定
綁定地址
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
返回:成功返回0,出錯返回-1;
查找綁定到套接字的地址
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp);
返回:成功返回0,出錯返回-1
獲取對方地址
#include<sys/socket.h>
int getpeername(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp);
返回:成功返回0,出錯返回-1
建立連接
伺服器端
#include <sys/socket.h>
int listen(int sockfd, int backlog);
backlog 指定進行客戶端連接排隊的隊列長度。
int accept(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict len);
客戶端
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t len);
下一節,編寫一個簡單的TCP程式