在网络编程中,“网络字节序”(Network Byte Order)指的是一种统一的字节排列方式,即大端字节序(Big-Endian),用于在网络上传输数据。这样做的目的是确保不同主机之间(可能采用不同的字节序)能够正确地解析数据。
#include <stdio.h>
void byteorder()
{
union{
short value;
char union_bytes[sizeof(short)];
}test;
test.value = 0x0102;
if( ( test.union_bytes[0] == 1 && test.union_bytes[1] == 2)
{
printf("big endian\n");
}else if( test.union_bytes[0] == 2 && test.union_bytes[1] == 1){
printf("little endian\n");
}else{printf("unknown...\n");
}
IP地址转换函数
struct in_addr
{
u_int32_t s_addr;
}
#include <arpa/inet.h>
int_addr_t inet_addr(const char* strptr);
int inet_aton(const char* cp,struct in_addr* inp);
char* inet_ntoa(struct in_addr in); // 不可重入
int inet_pton(int af, const char* src, void * dst);
const char* inet_ntop(int af, const void* src,char *dst,socklen_t cnt);
// 以上涉及的ip 地址的数字表示都是网络字节序
struct in_addr addr;
addr.s_addr = inet_addr("192.168.1.1");
char ip_str[INET_ADDRSTRLEN]; // 通常为 16 字节
if (inet_ntop(AF_INET, &addr, ip_str, INET_ADDRSTRLEN) != NULL)
{ printf("IP地址为: %s\n", ip_str); } else { perror("inet_ntop"); }
#include <stdio.h>
#include <arpa/inet.h>int main() {
const char *ip_str = "192.168.1.1"; // 待转换的 IPv4 地址字符串
struct in_addr addr;// 使用 inet_pton 进行转换
// AF_INET 表示 IPv4,&addr 是存放转换结果的地址
int result = inet_pton(AF_INET, ip_str, &addr);
if (result == 1) {
// 转换成功,addr.s_addr 存放的是网络字节序的地址
printf("IPv4地址转换成功!\n");
printf("网络字节序的地址值:0x%x\n", addr.s_addr);
} else if (result == 0) {
// 输入的地址字符串格式不正确
fprintf(stderr, "无效的IPv4地址格式: %s\n", ip_str);
return 1;
} else {
// 转换过程中出现错误
perror("inet_pton");
return 1;
}return 0;
}
1.创建socket
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);// 失败返回-1 并设置errno
domain: PF_INET (IPV4) 或者 PF_INET6(IPV6)对于unix 本地域协议族为PF_UNIX
type 指定服务类型 SOCK_STREAM(流服务)表示传输层使用TCP协议
SOCK_DGRAM (数据报服务)表示传输层使用udp协议
protocol 通常为0
2.命名socket
#include <sys/types.h>
#inclulde <sys/socket.h>
int bind(int sockfd,const struct sockaddr* my_addr,socklen_t addrlen);
bind 将my_addr所指的socket 地址分配给未命名的sockfd文件描述符,addrlen参数指出该sockaddr的长度
3.监听socket
#include <sys/socket.h>
int listen(int sockfd, int backlog);
sockfd 参数指定被监听的socket, backlog 参数提示内核监听队列的最大长度。
4.接受连接
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr* addr, socklen_t * addrlen);
sockfd 参数是执行过listen 系统调用的监听socket。addr 参数用来获取被接受连接的远端socket地址,该sockaddr 参数的长度由addrlen 参数指出
accetp 失败返回-1 并设置errno
5.发起连接
#include <sys/types.h>
#include <sys/socket.h>
int connect( int sockfd, const struct sockaddr* serv_addr, socklen_t addrlen);
sockfd 参数由socket系统调用返回一个socket,serv_addr 参数是服务器监听的socket地址,addrlen参数指定sockaddr 的长度。
connect 成功返回0,一旦成功建立连接,sockfd 就唯一标识了这个连接,客户端可以通过读写sockfd来与服务器通信。connect失败返回-1并设置errno
6.关闭连接
#include <unistd.h>
int close(int fd);
close 并不是直接关闭对应的fd 连接,而是将fd的引用计数减1.只有当fd的引用计数为0时,才可以真正关闭socket。一次fork系统调用默认将使父进程中打开的socket的引用加1,必须在子进程和父进程中都对socket执行close调用才能将连接关闭。
如果要立即关闭可以使用shutdown
#include <sys/socket.h>
int shutdown(int sockfd, int howto);
sockfd 是待关闭的socket howto 决定了shutdown的行为
SHUT_RD 应用程序不可以再对sockfd进行读操作
SHUT_WR 不可以写操作
SHUT_RDWR 同事关闭读写
成功返回0失败返回-1并设置errno