C | 网络编程 | socket

主机字节序与网络字节序


在这里插入图片描述

主机字节序与网络字节序之间的转换

常用结构体

在这里插入图片描述

在这里插入图片描述

  • gethostbyname()可用于获取主机的hostent
  • gethostbyname(const char *name)可以对域名解析获得IP地址,更加灵活。

在这里插入图片描述

示例

  struct sockaddr_in servaddr; // 服务端地址信息的数据结构。
  memset(&servaddr, 0, sizeof(servaddr));   //对结构体清零
  servaddr.sin_family = AF_INET;                // 协议族,在socket编程中只能是AF_INET。
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 任意ip地址。
  // servaddr.sin_addr.s_addr = inet_addr("192.168.190.134"); // 指定ip地址。
  servaddr.sin_port = htons(atoi(argv[1])); // 指定通信端口 atoi将数字字符串转化为整数

  • void memset(void s, int ch, size_t n);
    函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
    memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法 。
  • INADDR_ANY
    转换过来就是0.0.0.0,泛指本机的意思,也就是表示本机的所有IP,因为有些机子不止一块网卡,多网卡的情况下,这个就表示所有网卡ip地址的意思。

bind()函数

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

  • 作用:给我们的socket绑定端口号与具体地址
  • 示例:
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0。
  • 其中listened为一个socket的值; servaddr为一个sockaddr结构体(这里由sockaddr_in结构体转换);第三个参数为第二个参数的长度。
  • 服务端程序的端口释放后可能会处于TIME_WAIT状态,需等待两分钟后才能被使用,解决方式:
int opt = 1;
unsigned int len = sizeof(opt);
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,len);

listen(),connect(),accept()函数

当使用tcp服务器使用socket创建通信文件描述符,bind绑定了文件描述符,服务器ip和端口号,listen将服务器端的主动描述符转为被动描述符进行监听之后,接口accept通过三次握手与客户端建立连接

  • 服务端在调用listen之前,客户端不能向服务端发起连接请求
  • 服务端调用listen之后,服务端socket开启监听客户端的连接
  • 客户端调用connect向服务端发送连接请求
  • 在TCP底层,客户端和服务端握手后建立起通信通道,如果有多个客户端请求,在服务端就会形成一个已准备好的连接队列
  • 服务端调用accept从队列中获取一个已准备好的连接,函数返回一个新的socket,新的socket用于与客户端通信,listen的socket只负责监听客户端的连接请求

listen()函数

 int listen(int sockfd, int backlog);
  • 作用: 当socket函数创建一个套接字时,它被假设为一个主动套接字,也就是说,它是一个将调用connect连接的客户套接字。listen函数把一个未连接的套接字转换成一个被动套接字,指示内核应该接受指向该套接字的连接请求。
  • listen函数的第二个参数规定了内核应为相应套接字排队的最大连接个数(backlog+1)

本函数通常应该在调用socket和bind之后,并在调用accept之前被调用。

connect()函数

  int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd是由socket函数返回的套接字描述符,第二个、第三个参数分别是一个指向套接字地址结构的指针和结构的大小。

客户端在调用connect前不必非得调用bind函数,因为如果需要的话,内核会确认源IP地址,并选择一个临时端口作为源端口,通常我们都不会在客户端调用bind函数。

accept()函数

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. addr: 用于记录发起连接请求的那个客户端的IP端口
    建立连接时服务器的TCP协议会自动解析客户端发来的数据包,从中获取客户端的IP和端口号
    c. addrlen表示第二个参数addr的大小

这里如果服务器应用层需要用到客户端的 IP和端口号,可以给accept指定第二个参数addr,以获取TCP链接时的客户端ip和端口号;如果服务器应用层不需要,则写NULL即可
addr的结构体类型为 struct sockaddr,在listen函数详解中我们有介绍过,由于这个结构体用起来不是非常方便,我们需要定义struct sockaddr_in结构体来使得sockaddr结构体操作更为便捷。

send()函数

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • 作用:用于把数据通过socket发送给对端。不论是客户端还是服务端,应用程序都用send函数来向TCP连接的另一端发送数据。

参数说明

  • sockfd:已建立好连接的socket。
  • buf:需要发送的数据内存地址,可以是C语言基本数据类型变量的地址,也可以是数组、结构体、字符串、内存中有什么就发什么。
  • len:需要发送的数据长度,为buf中的有效数据长度。
  • flags填0,其他参数意义不大。

函数返回已发送的字符数,出错时返回-1,错误信息errno被标记。
注意:就算是网络断开,或socket已被对端关闭,send函数不会立即报错,要过几秒才会报错。
如果send函数返回的错误(<=0),表示通信链路已不可用。

recv()函数

int recv( SOCKET s, char *buf, int len, int flags);
  • 作用:recv函数用于接受对端通过socket发送过来的数据。不论是客户端还是服务端,应用程序都用recv函数接收来自TCP连接的另一端发送过来数据。

参数说明

  • sockfd:已建立好连接的socket。
  • buf:用于接受的数据内存地址,可以是C语言基本数据类型变量的地址,也可以是数组、结构体、字符串,只要是一块内存就好。
  • len:需要接收的数据长度,不能超过buf的大小,否则内存溢出。
  • flags填0,其他参数意义不大。

函数返回已接受的字符数。出错时返回-1,失败时不会设置errno的值。
如果socket的对端没有发送数据,recv函数就会等待,如果对端发送了数据,函数返回接收到的字符数。出错时返回-1。如果socket对端关闭,返回值为0。
如果recv函数返回的错误(<=0),表示通信通道已不可用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值