日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

C语言网络编程:bind函数详解

發布時間:2023/11/27 生活经验 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言网络编程:bind函数详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

            • 函數功能
            • 函數頭文件
            • 函數使用
            • 函數參數
            • 函數舉例
            • 為什么需要bind函數
            • 服務器如何知道客戶端的ip和端口號
            • htons函數
            • `htons`兄弟函數`htonl`,`ntohs`,`ntohl`
            • 為什么要進行端口的大小端序的轉換
            • `inet_addr`函數

函數功能

bind API能夠將套接字文件描述符、端口號和ip綁定到一起
注意:
綁定的一定是自己的 ip和和端口,不是對方的;比如對于TCP服務器來說綁定的就是服務器自己的ip和端口

函數頭文件
 #include <sys/types.h>          /* See NOTES */#include <sys/socket.h>
函數使用

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函數參數
  • sockfd 表示socket函數創建的通信文件描述符
  • addrlen 表示所指定的結構體變量的大小
  • addr 表示struct sockaddr的地址,用于設定要綁定的ip和端口
    struct sockaddr {sa_family_t sa_family;char        sa_data[14];
    }
    
    sa_family 用于指定AF_***表示使用什么協議族的ip
    sa_data 存放ip和端口
    這里有一個問題,直接向sa_data中寫入ip和端口號有點麻煩,內核提供struct sockaddr_in結構體進行寫入,通過/usr/include/linux/in.h可以看到結構體原型
    使用該結構體時需要包含<netinet/in.h>頭文件,且sockaddr_in結構體是專門為tcp/ip協議族使用,其他協議族需要使用其對應的轉換結構體,比如“域通信協議族” 使用的是sockaddr_un結構體
    struct sockaddr_in {__kernel_sa_family_t  sin_family;     /* Address family               */__be16                sin_port;       /* Port number                  */struct in_addr        sin_addr;       /* Internet address             *//* Pad to size of `struct sockaddr'. 設置IP端口號這個成員暫時用不到 */unsigned char         __pad[__SOCK_SIZE__ - sizeof(short int) -sizeof(unsigned short int) - sizeof(struct in_addr)];
    };/* Internet address.填補相比于struct sockaddr所缺的字節數,保障強制轉換不要出錯 */
    struct in_addr {__be32  s_addr; // __be32是32位的unsigned int ,因為ipv4是無符號32位整型 
    };
    
    可以看到以上sockaddr_in結構體中存放的端口和ip是分開的,所以設置起來非常方便,使用struct sockaddr_in設置后,讓后將其強制轉換為struct sockaddr類型,然后傳遞給bind函數即可
函數舉例
struct sockaddr_in addr;
addr.sin_family = AF_INET; //設置tcp協議族
addr.sin_port = htons(6789); //設置端口號
addr.sin_addr.s_addr = inet_addr("192.168.1.105"); //設置ip地址ret = bind(skfd, (struct sockaddr*)&addr, sizeof(addr));

如果是跨局域網或者城域網通信,這里設置的ip地址一定為通信設備所在路由器的外網ip地址。

如下c代碼

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h> //struct sockadd_in 結構體的頭文件
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>void print_err(char *str, int line, int err_no) {printf("%d, %s :%s\n",line,str,strerror(err_no));_exit(-1);
}int main()
{int skfd = -1;skfd = socket(AF_INET, SOCK_STREAM, 0);if ( -1 == skfd) {print_err("socket failed",__LINE__,errno);}struct sockaddr_in addr;addr.sin_family = AF_INET; //設置tcp協議族addr.sin_port = htons(6789); //設置端口號addr.sin_addr.s_addr = inet_addr("192.168.102.169"); //設置ip地址int ret = bind(skfd, (struct sockaddr*)&addr, sizeof(addr));if ( -1 == ret) {print_err("bind failed",__LINE__,errno);}return 0;
}
為什么需要bind函數

bind函數就是讓套接字文件在通信時使用固定的IP和端口號(針對服務器來說)
可以看到如上實現代碼,調用socket函數創建的套接字僅僅執行了通信等協議,但是并沒有指定通信時所需的ip地址和端口號

  • ip 是對方設備的唯一標識
  • 端口號 區分同一臺計算機上的不同的網絡通信進程

如果不調用bind函數指定ip和端口,則會自己指定一個ip和端口,此時違背了TCP通信的可靠性和面向連接的特點。

服務器如何知道客戶端的ip和端口號

可以通過上文TCP通信模型中看到,客戶端通信時不需要指定ip和端口號,直接創建一個socket套接字文件描述符即可參與通信。
此時當客戶端和服務器建立連接的時候,服務器會從客戶的數據包中提取出客戶端ip和端口,并保存起來,如果是跨網通信,那么記錄的就是客戶端所在路由器的公網ip

htons函數
  • #include <arpa/inet.h>
  • uint16_t htons(uint16_t hostshort); 函數全拼為host to net short
  • 函數功能
    a. 將端口從"主機端序" 轉為 “網絡端序”
    b. 如果給定的端口不是short,則轉為short
  • 返回值: 函數的調用永遠都是成功的,返回轉換后的端口號
htons兄弟函數htonl,ntohs,ntohl
  • htonlhtons唯一的區別時,轉換完的端口號為long
  • ntohshtons恰好相反,是從網絡字節序轉換為主機字節序
  • ntohl 表示從網絡字節轉換為主機序,同時轉換完的端口號為long
為什么要進行端口的大小端序的轉換

大端序:
大端模式,是指數據的高字節保存在內存的低地址中,而數據的低字節保存在內存的高地址中,這樣的存儲模式有點兒類似于把數據當作字符串順序處理:地址由小向大增加,而數據從高位往低位放;
小端序:
小端模式,是指數據的高字節保存在內存的高地址中,而數據的低字節保存在內存的低地址中,這種存儲模式將地址的高低和數據位權有效地結合起來,高地址部分權值高,低地址部分權值低,和我們的邏輯方法一致。

大小端序是由具體的操作系統來決定的
可以使用如下代碼測試系統是大端還是小端:

#include <stdio.h>
int main()
{int a = 1;char pc = *(char*)(&a);if (pc == 1)printf("第一個字節為1,小端存儲\n");elseprintf("第一個字節為0,大端存儲\n");return 0;
}

同樣,網絡通信的時候發送端計算機和接收端計算機可能端序不一致,比如發送者是大端序,接受者是小端序,如果通信時數據的端序處理不好很可能出現亂碼,甚至無法接收到數據。
如果發送者和接受者端序一致則也能夠正常傳輸數據,不用htons函數進行轉換,不過保證數據序列正確的得進行傳輸,建議使用htons函數進行端口號的轉換

inet_addr函數
  • <sys/socket.h> <netinet/in.h> <arpa/inet.h>
  • in_addr_t inet_addr(const char *cp);
  • 函數功能:
    a. 將字符串形式的IP "192.168.102.169"轉換為IPV4的32位無符號整型數的IP
    b. 將無符號整型數的ip,從主機端序轉為網絡端序
  • 參數:字符串形式的ip
  • 返回值:永遠成功,返回網絡端序的、32位無符號整型數的ip

總結

以上是生活随笔為你收集整理的C语言网络编程:bind函数详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。