1、程式設計模型函數化

函數學習
1)建立套接字
函數名:socket
函數原型:Int socket(int domain,int type,int protocol);
函數功能:建立套接字
所屬頭檔案:<sys/types.h>、<sys/socket.h>
傳回值:成功:傳回對應于新套接字的檔案描述符或者套接字的id,失敗:傳回錯誤編碼
參數說明:domain:有一系列可取值;type:建立的套接字協定的類型;protocal:協定
解釋:
int domain,表示套接字要使用的協定簇,協定簇在檔案linux/socket.h有詳細定義,常用的協定簇:
AF_UNIX(本機通信);
AF_INET(TCP/IP -IPv4);
AF_INET6(TCP/IP - IPv6);
其中type參數指的是套接字類型;常用的類型有:
SOCK_STREAM(TCP流);
SOCK_DGRAM(UDP資料報);
SOCK_RAW(原始套接字);
最後一個protocol一般設定為0,也就是當确定套接字使用的協定簇和類型時,這個參數的值就為0,但是有時候建立原始套接字時,并不知道要使用的協定簇和類型,也就是domain參數未知情況下,這時protocol這個參數就起作用了,它可以确定協定的種類。
socket是一個函數,那麼它也有傳回值,當套接字建立成功時,傳回套接字,失敗傳回“-1”,錯誤代碼則寫入“errno”中。
2)綁定套接字
解釋:Socket套接字位址:是一個資料結構,基于TCP傳輸協定為例,其資料結構裡面包含了:
#include<netinet/in.h>
struct sockaddr_in
{
unsigned short sin_family;//位址類型,對于基于TCP/IP傳輸協定的通信,該值隻能是AF_INET;
unsigned shot int sin_port;//表示端口号,範圍在0~65535之間;
struct in_addr sin_addr;//32位的IP位址;
unsigned char sin_zero[8];//表示填充位元組,一般該值為0;
};
例子:
struct sockaddr_in Lewis;
Lewis.sin_family = AF_INET;
Lewis.sin_port = htons(80);
Lewis.sin_addr.s_addr = inet_addr("202.96.134.133");
memset(Lewis.sin_zero,0,sizeof(Lewis.sin_zero));
對于
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);
對于選項INADDR_ANY,就是指的是0.0.0.0的位址,表示所有位址,任意位址,用于一台電腦上有多個網卡的情況,友善管理,管理一個套接字就行,不管資料從哪個網卡過來,隻要是綁定的端口号過來的資料,都可以接收;而用戶端不能使用INADDR_ANY選項;htons #include <arpa/inet.h>
uint16_t htons(uint16_t hostshort);
功能: 将一個無符号短整型數值轉換為網絡位元組序,即大端模式(big-endian)
htons 是把你機器上的整數轉換成“網絡位元組序”, 網絡位元組序是 big-endian,也就是整數的高位位元組存放在記憶體的低位址處。而我們常用的 x86 CPU (intel, AMD) 電腦是 little-endian,也就是整數的低位位元組放在記憶體的低位元組處。
舉個例子:假定你的port是 0x1234, 在網絡位元組序裡 這個port放到記憶體中就應該顯示成 addr addr+1 0x12 0x34 而在x86電腦上,0x1234放到記憶體中實際是: addr addr+1 0x34 0x12 htons 的用處就是把實際記憶體中的整數存放方式調整成“網絡位元組序”的方式。
htonl() #include <arpa/inet.h>
功能:将主機的無符号長整形數轉換成網絡位元組順序。
uint32_t htonl(uint32_t hostlong);
inet_addr() 将一個字元串格式的ip位址轉換成一個uint32_t數字格式,但是需要注意的是, 這個函數的傳回值在大小端機器上是不同的;
例如輸入一個"192.168.0.1"的字元串, 在記憶體中的排列(位元組從低到高) 0xC0, 0xA8 ,0x00 ,0x4A。 那麼在小端序機器上,傳回的數字就是0x4a00a8c0 , 而在大端序機器上則是0xc0a8004a
函數名:bind
函數原型:Int Bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);
函數功能:綁定套接字:将ip位址與套接字相綁定
所屬頭檔案:<sys/types.h>、<sys/socket.h>
傳回值:成功:傳回對應于新套接字的檔案描述符或者套接字的id;失敗:傳回錯誤編碼
參數說明:sockfd:要綁定套接字的fd;addr:将套接字與那個位址進行綁定;addrlen:位址長度
網絡位元組序:
3)監聽
listen
int listen(int sockfd,int backlog)
作用:1、用來指明伺服器已經做好了準備,可以用來接收客戶機的請求了。2、用來設定伺服器可以接受多少個客戶機的連接配接請求
參數:sockfd與之關聯的套接字的fd。Backlog:客戶機的數目,即允許多少個客戶機來進行連接配接。
成功:傳回0,失敗:傳回-1
4)等待連接配接
Accept
int accept(int sockfd,struct sockaddr *restrict addr,socklen_t *restrict len);
作用:等待客戶機來進行連接配接,如果無客戶機來連接配接,則導緻伺服器在這裡阻塞。
參數:sockfd:建立的套接字的fd。Addr:如果有客戶機來進行連接配接,那麼通過本位址來傳回客戶機的位址。Len:接收到客戶機的位址的長度
成功:傳回新的套接字的描述符。後面在發送和接收資料時用這個新的fd來進行操作。
5)發送資料
函數名:Send
ssize_t send(int sockfd,const void *buf,size_t nbytes,int flags);
作用:發送資料
參數:sockfd:新的套接字的fd,buf:要發送資料的位址,nbytes:要發送資料的長度,flags:标志
6)接收資料
Recv
ssize_t recv(int sockfd,void *buf,size_t nbytes,int flags)
參數:sockfd:新的套接字的fd,buf:要存資料的位址,nbytes:希望接收多大量的資料,flags:标志
7)關閉連接配接
Close
8)連接配接伺服器
Connect
int connect (int sockfd,const struct sockaddr *addr,socklen_t len)
參數:新建立的套接字的fd,addr:儲存的伺服器的位址,len:伺服器位址的長度
成功:傳回0
失敗:傳回-1
9)
#include <arpe/inet.h>
int inet_pton(int family, const char *strptr, void *addrptr); //将點分十進制的ip位址轉化為用于網絡傳輸的數值格式
傳回值:若成功則為1,若輸入不是有效的表達式則為0,若出錯則為-1
const char * inet_ntop(int family, const void *addrptr, char *strptr, size_t len); //将數值格式轉化為點分十進制的ip位址格式
傳回值:若成功則為指向結構的指針,若出錯則為NULL
tcp_server.c
修改:
tcp_client.c