一.定義
Socket(套接字)是網絡編程的核心,它允許不同主機或同一主機的不同進程之間進行通信,Socket API 提供了一套標準的接口,支持 TCP、UDP、IP 等協議
分為以下三個類型:
SOCK_STREAM:
用于tcp協議,可靠、面向連接、字節流,使用場景:HTTP、FTP、SSHSOCK_DGRAM:
用于udp協議,不可靠、無連接、數據報,使用場景:DNS、視頻流、游戲SOCK_RAW:
用于IP/ICMP 原始套接字(直接訪問網絡層),使用場景:網絡嗅探、自定義協議
地址結構:
IPV4:? struct sockaddr_in
struct sockaddr_in {sa_family_t sin_family; // 地址族(AF_INET)in_port_t sin_port;// 端口號(16位,需用 htons() 轉換)struct in_addr sin_addr; // IP地址(32位,需用 inet_addr() 或 htonl())char sin_zero[8]; //填充(保持與 sockaddr 大小一致)
};
IPV6:struct sockaddr_in6
通用結構:struct?sockaddr
struct sockaddr {sa_family_t sa_family; //地址族(AF_INET, AF_INET6, AF_UNIX)char sa_data[14]; //實際地址數據
};
二.API接口(核心)
socket():
作用:創建套接字
//頭文件:
#include <sys/socket.h>int socket(int domain,int type,int protocol);domain --- 協議族(AF_INET、AF_INET6、AF_UNIX)
type --- 套接字類型(SOCK_STREAM、SOCK_DGRAM)
protocol --- 控制,通常填 0(自動選擇,如 IPPROTO_TCP)返回值:
-1 --- 創建失敗
其他 --- 創建成功,并返回socketfd(套接字描述符)
舉例:
#include <iostream>
#include <sys/socket.h>int socketfd = socket(AF_INET,SOCK_STREAM,0);
//檢查:
if(socketfd == -1){std::cerr<<"socket creation failed"<<std::endl;exit(EXIT_FAILURE);
}
//創建成功
bind():
綁定IP和端口
//頭文件:
#include <sys/socket.h>int bind(int socketfd,const struct sockaddr* addr,socklen_t addrlen);//參數:
socketfd --- 套接字描述符
addr --- 指向 sockaddr_in 或 sockaddr_in6 的指針(需強制轉換)
addrlen --- 地址結構的大小(sizeof(struct sockaddr_in))//返回值:
-1 --- 綁定失敗
其他(0)--- 綁定成功
舉例:
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = INADDR_ANY;if(bind(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)
{ perror("bind failed");exit(EXIT_FAILURE);
}
listen():
監聽連接(TCP)
#include <sys/socket.h>int listen(int sockfd,int backlog);//參數:
sockfd --- 套接字描述符
backlog --- 等待連接隊列的最大長度//返回值:
-1 --- 失敗
其他(0)--- 成功
舉例:
if (listen(sockfd, 5) == -1) {perror("listen failed");exit(EXIT_FAILURE);
}
accept():
接收連接
#include <sys/socket.h>int accept(int sockfd,struct socketaddr* addr,socklen_t* addrlen);//參數:
sockfd --- 套接字描述符
addr --- 用于存儲客戶端地址
addrlen --- 地址結構大小(需先初始化)//返回值:
-1 --- 連接失敗
其他 --- 連接成功,返回的是新的套接字描述符
舉例:
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int connet_fd = accpet(sockfd,(struct socketaddr*)&client_addr,&client_len);
if(connet_fd == -1)
{perror("accept failed");exit(EXIT_FAILURE);
}
//連接成功
connect():
用戶向服務器發起連接
#include <sys/socket.h>int connect(int sockfd,const struct sockaddr *addr, socklen_t addrlen);//參數:
sockfd --- 套接字描述符
addr --- 服務器地址
addrlen --- 地址結構大小//返回值:
-1 --- 連接失敗
其他(0)--- 連接成功
舉例:
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htos(8080);
//解析IP:
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); //連接并判斷:
if(connect(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)) == -1)
{perror("connect failed");exit(EXIT_FAILURE);
}
//連接成功
send/recv:
TCP數據收發
#include <sys/socket.h>//發送數據:
ssize_t send(int sockfd,const void *buf, size_t len, int flags);//接收數據:
ssize_t recv(int sockfd,void *buf, size_t len, int flags);//buf內容要填充的,不能用const//參數:
sockfd --- 已連接的套接字
buf --- 數據緩沖區
len --- 數據長度
flags --- 可選標志(如 MSG_WAITALL 阻塞直到收滿)//返回值:
-1 --- 失敗
其他 --- 成功 并返回發送/接收的字節數
舉例:
char buffer[1024];//緩沖區
ssize_t bytes_received = recv(connect_fd,buffer,sizeof(buffer),0);
if(bytes_received == -1)
{perror("recv failed");
}
else
{buffer[bytes_received] = '\0'; // 確保字符串終止printf("Received: %s\n", buffer);
}
sendto/recvfrom:
UDP數據收發
#include <sys/socket.h>//發送數據:
ssize_t sendto(int sockfd,const void* buf,size_t len,int flags,const struct sockaddr* dest_addr,socklen_t addrlen);//接收數據:
ssize_t recvfrom(int sockfd,void* buf,size_t len,int flags,struct sockaddr* src_addr,socklen_t* socklen);//參數:
很多之前我們已經講過了,講下幾個沒講的
dest_addr / src_addr --- 目標/源地址//返回值:
-1 --- 發送、接收失敗
其他 --- 返回發送/接收的字節數
舉例:
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[1024];
ssize_t bytes_recvfrom = recvfrom(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&client_addr,&client_len);
if(bytes_recvfrom == -1)
{perror("recvfrom failed");
}
//接收成功
close()
關閉套接字
#include <unistd.h>//Linux系統下:
int close(int sockfd);//補充:Windows系統下
#incluide <winsock2.h>
int closesocket(SOCKET sockfd);//也是關閉連接,但是可以自己選擇
int shutdown(int sockfd, int how);//參數:
how --- 1.SHUT_RD:關閉讀取 2.SHUT_WR:關閉寫入 3.SHUT_RDWR:完全關閉
掌握這些 API 后,你可以實現基本的?TCP 服務器/客戶端?和?UDP 通信了
最后,感謝你的支持!!!