C语言网络编程:accept函数详解
生活随笔
收集整理的這篇文章主要介紹了
C语言网络编程:accept函数详解
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 前言
- 函數描述
- 代碼實例
- 如何得到客戶端的IP 和 端口號
前言
當使用tcp服務器使用socket創建通信文件描述符,bind綁定了文件描述符,服務器ip和端口號,listen將服務器端的主動描述符轉為被動描述符進行監聽之后,接口accept通過三次握手與客戶端建立連接
TCP 編程模型如下:
函數描述
#include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);- 函數功能:
被動監聽客戶端發起的tcp連接請求,三次握手后連接建立成功。客戶端connect函數請求發起連接。
連接成功后服務器的tcp協議會記錄客端的ip和端口,如果是跨網通信,記錄ip的就是客戶端所在路由器的公網ip - 返回值:
成功:返回一個通信描述符,專門用于與連接成功的客戶端進行通信。
失敗:返回-1 ,并設置errno - 函數參數:
a.sockfd已經被listen轉為了被動描述符的“套接字文件描述符”,專門用于客戶端的監聽,入股sockfs沒有被listen函數轉為被動描述符,則accept是無法將其用來監聽客戶端連接的。
套接字文件描述符默認是阻塞的,即如果沒有客戶端請求連接的時候,此時accept會阻塞,直到有客戶端連接;如果不想套接字文件描述符阻塞,則可以創建套接字 socket函數 時指定type為SOCK_NOBLOCK
b.addrlen表示第二個參數addr的大小,不顧要求給定地址
c.addr: 用于記錄發起連接請求的那個客戶端的IP端口
建立連接時服務器的TCP協議會自動解析客戶端發來的數據包,從中獲取客戶端的IP和端口號
這里如果服務器應用層需要用到客戶端的 IP和端口號,可以給accept指定第二個參數addr,以獲取TCP鏈接時的客戶端ip和端口號;如果服務器應用層不需要,則寫NULL即可
addr的結構體類型為struct sockaddr,在listen函數詳解中我們有介紹過,由于這個結構體用起來不是非常方便,我們需要定義struct sockaddr_in結構體來使得sockaddr結構體操作更為便捷。具體使用如下:struct sockaddr_in naddr = {0};int nsize = sizeof(naddr); int cfd = accept(sockfd, (struct sockaddr *)&naddr, &nsize);
代碼實例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#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, ret = -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 = 6789; //設置端口號addr.sin_addr.s_addr = inet_addr("192.168.102.169"); //設置ip地址ret = bind(skfd, (struct sockaddr*)&addr, sizeof(addr));if ( -1 == ret) {print_err("bind failed",__LINE__,errno);}/*將套接字文件描述符從主動轉為被動文件描述符,然后用于被動監聽客戶端的連接*/ret = listen(skfd, 3);if ( -1 == ret ) {print_err("listen failed", __LINE__, errno);}/*被動監聽客戶端發起的tcp連接請求,三次握手后連接建立成功*/int cfd = -1;struct sockaddr_in caddr = {0}; //為應用層獲取客戶端的IP和端口號int csize = 0;cfd = accept(skfd, (struct sockaddr*)&caddr, &csize);if (-1 == cfd) {print_err("accept failed", __LINE__, errno);}return 0;
}
如何得到客戶端的IP 和 端口號
比如程序中想要打印客戶端的ip和端口號,這里就需要使用到ntohs和inet_ntoa函數進行端序轉換,因為客戶端的端口和ip是服務器的TCP協議,從客戶端發送端網絡數據包中提取出來,網絡數據包的端序屬于網絡端序,主機接收到數據后如果想要使用的話,就必須從網絡端序轉為主機端序。
舉例如下:
struct sockaddr_in caddr = {0};int csize = sizeof(caddr);
cfd = accept(sockfd, (struct sockaddr *)&caddr, &csize);printf("cport = %d, caddr = %s\n", ntohs(caddr.sin_port),inet_ntoa(caddr.sin_addr));
總結
以上是生活随笔為你收集整理的C语言网络编程:accept函数详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 老式十几年前没有前加力四不像拖拉机车值多
- 下一篇: C语言网络编程:listen函数详解