栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

socket 常用操作相关函数介绍(C语言)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

socket 常用操作相关函数介绍(C语言)

数据结构和字节序 基础数据结构
  • 1基础数据结构和函数:地址 表示数据结构
    struct sockaddr_in{
    _SOCKADDR_COMMON(sin);
    in_port_t sin_port; //端口号
    struct in_addr sin_addr; // IP地址
    }
    典型的填充IP地址的数据结构如下:
struct sockaddr_in addr;

addr.sin_family  =AF_INET;
addr.sinport = htons(80);
addr.sin_addr.s_addr  = inet_addr("192.168.0.1"); 

sin_port 和 sin_addr.s_addr 两个值都是多字节的整数,socket 规定这里必须使
用网络字节序。

网络 字节序和本地字节序的转换
  • 字节序:在网络应用中,字节序是一个必须考虑的因素,因为不同机器类型可能采用不同标准的
    字节序,所以均须按照网络标准转化。网络传输的标准叫做网络字节序,实际上是大端序。而我们常用的 X86 或者 ARM 往往都是小端序。
    手工进行字节序的转换往往是不方便的,对于可移植的程序来说更是如此。总是需要知
    道自己的本地主机字节序也是很麻烦的。所以,系统提供了四个固定的函数,用来在本地字
    节序和网络字节序之间转换。这四个函数包含在头文件中,分别是:
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong):
uint16_t ntohs(uint16_t netshort);

这四个函数功能依次列举如下:
32 位整数从主机字节序转换为网络字节序;
16 位整数从主机字节序转换为网络字节序;
32 位整数从网络字节序转换为主机字节序;
16 位整数从网络字节序转换为主机字节序。

主机名和地址转换函数

在实际的网络编程中,往往需要在IP地址的点分十进制表示和二进制之间相互 转化,也需要进行主机名和地址的转换,系统提供了一系列的函数,一般需要包含头文件
传输中需要二进制,显示时需要十进制

in_addr_t inet_addr(const char *cp)

这个函数将一个点分十进制的 IP 地址字符串转换成 in_addr_t 类型,该类型实际上是一个 32 位无符号整数,事实上就是前文提到的 struct in_addr 结构中的 s_addr 域的数据类型。
注意这个二进制表示的 IP 地址是网络字节序的。这个函数其实在前文举例填充 struct sockaddr_in 的时候用过了。192.168.0.1 在 PC 上会被转换成 0x0100A8C0。

char *inet_ntoa(struct in_addr in)

此函数可以将结构 struct in_addr 中的二进制 IP 地址转换为一个点分十进制表示的字符
串,返回这个字符串的首指针。使用起来很方便。但是要注意,它返回的缓冲区是静态分配
的,在并发或者异步使用时要小心,因为缓冲区随时可能被其它调用改写。

  • 通过主机名获取IP地址
    实际应用中,很多时候得到的是通信另一方的主机名,所以需要将主机名转换为IP地址,传统上有两个函数生命在中来进行这个 操作。
struct hostent *gethostbyname(const char *name);

直接根据主机名字符串返回一个 struct hostent 结构。

socket常用操作
  • socket的常用操作 主要包括:
  • 创建socket
  • 绑定地址和端口
  • 连接服务器
  • 设置socket为监听模式
  • 接收连接
  • 网络数据的读和写
1.创建socket

创建socket的函数原型:

int socket(int domain, int type, int protocol);

其中,

  • domain代表了socket使用的地址类型(IPV4 IPV6)ipV4使用AF_INET
  • type代表了socket类型(UDP TCP)UDP:SOCK_DGRAM TCP:SOCK_STREAM
  • protocol:协议类型,目前一般为0
    TCP例子:
sock_fd = socket(AF_INET, SOCK_STREAM, 0);

UDP例子:

sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
2.绑定地址和端口

绑定函数原型:

    int bind(int socket,const struct sockaddr *address,socklent address_len);

参数说明:

  • socket指向socket的文件描述符
  • address:指向struct sockaddr 结构的指针,如果填入IP地址,则为struct sockaddr_in
  • address_len address内容的长度
    示例:
struct sockaddr_in server_addr;
(void)memset(&server_addr, 0, sock_len);  //从server_addr开始,为连续的n个内存地址赋值0 
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(80);
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) {
 perror("bind(2) error");
 goto err;
}
3.连接服务器

函数原型:

int connect(int socket, const struct sockaddr *address, socklent address_len);

TCP示例:

struct sockaddr_in server_addr;
(void)memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(7007);
server_addr.sin_addr.s_addr = inet_addr("192.168.0.1");
if (connect(conn_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
 perror("connect(2) error");
 goto err;
}
4.监听模式

函数原型:

int  listen(int socket,int backlog);
  • socket:指向socket的文件描述符
  • 等待连接的队列长度,实际上队列会大于 这个数字,通常取5
5.接收连接

函数原型:

int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
  • socket:指向socket的文件描述符
  • address:指向struct sockaddr 结构的指针,如果填入IP地址,则为struct sockaddr_in
  • address_len 与前面的函数不同,这里是一个指向 socklen_t 类型的指针,这个存储区域
    用来返回上一个参数返回的地址数据结构的长度
struct sockaddr_in client_addr;
socklen_t sock_len;
„„
while (true) {
 conn_sock = accept(server_sock, (struct sockaddr *)&client_addr, &sock_len);
 if (conn_sock < 0) {
 if (errno == EINTR) {
 
 continue;
 }
 break;
 }
 }
6.读数据函数
  • read(2)、recv(2)、recvfrom(2)和 recvmsg(2)
ssize_t read(int fd, void *buf, size_t count);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

对于这四个函数的解析:
write(2)、send(2)、sendto(2)和 sendmsg(2)

ssize_t write(int fd, const void *buf, size_t count);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
 const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/604164.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号