c++ socket、 listen、accept、recv 、send、 connect函数记录

socket

int socket (int __domain, int __type, int __protocol);
  1. __domain为协议域,又称协议族,我们最常用的有AF_INET、AF_INET6(也可以写作为PF_INET、PF_INET6),分别代表IPv4地址和IPv6地址。

  2. __type为数据传输方式或套接字类型,最常见的有SOCK_STREAM和 SOCK_DGRAM,其中SOCK_STREAM为面向连接的数据传输方式,是基于TCP的协议,数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送,但效率相对较慢;而SOCK_DGRAM是无连接的数据传输方式,是基于UDP的协议,即只管传输数据,不作数据校验,如果数据在传输中损坏,或者没有到达另一台计算机,是没有办法补救的。

  3. __protocol为传输协议,对应上述的__type,常用的有IPPROTO_TCP 和 IPPTOTO_UDP分别代表TCP和UDP协议。而系统会根据__type的值自行选择,因此该项一般可直接指定为0。

  4. socket返回的值是一个文件描述符,由于0,1,2,都被占用,所以是从3开始,错误时返回-1;

bind()和connect()函数

bind()函数用于服务器端,用来绑定套接字和自己的ip地址和端口;
connect()函数用于客户端,旨在连接套接字和服务器端的IP地址和端口。
两个函数的返回值表示是否成功(0表示成功,-1表示错误)
函数原型如下:

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
  1. sockfd为socket返回的文件描述符。

  2. addr为一个const struct sockaddr *指针,由于兼容性的原因,这里我们只能先使用sockaddr_in 结构体来定义相应的IP地址和端口号,然后再强制转换为 sockaddr 类型的方式。

  3. addrlen为2中结构体的大小,可由sizeof()计算给出。

在使用上述两个函数之前,需要先给sockaddr_in 结构体中的成员赋值,其中sockaddr_in 结构体的成员变量如下:

struct sockaddr_in{
    sa_family_t     sin_family;   //协议族,和socket()函数中一致即可
    uint16_t        sin_port;     //16位的端口号,尽量保证端口号在1024~65536之间
    struct in_addr  sin_addr;     //32位IP地址
    char            sin_zero[8];  //不使用,一般用0填充
};

listen()和accept()函数

在服务器端,绑定了套接字后,还需通过listen()函数进入到监听状态。
监听状态下调用accept()函数进行接收,当收到来自客户端的请求后就可以建立连接了。
listen()函数返回值0表示成功,-1表示失败

int listen(int __fd, int __n);
  1. __fd为socket返回的文件描述符。

  2. __n为请求队列的最大长度,也即缓冲区大小。当socket正在处理客户端请求时,如果有新的请求到来,只能被放进缓冲区,这个参数就是表明能接受多少个客户端请求。

accept()函数返回一个新的文件描述符,表示和对应的客户端进行通信。

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  1. __fd为socket返回的文件描述符。

  2. addr为一个const struct sockaddr *指针,由于兼容性的原因,这里我们只能先使用sockaddr_in 结构体来定义相应的IP地址和端口号,然后再强制转换为 sockaddr 类型的方式。

  3. addrlen为一个指针,解引用后值为2中结构体的大小,可由sizeof()计算给出。

send()、recv()、read()和write()函数

send()和write()返回值为向fd写入的字节数,=0时断开连接,<0时出错。
recv()和read()返回值为从fd读取的字节数,=0时断开连接或读取结束,<0时出错。

ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void*buf,size_t nbytes);
  • read:负责从描述符fd中读取内容,当读取成功时,read返回实际所读的字节数(大于0);如果返回的值为0,表示已经读到文件结束了;如果返回的值小于0,则出现错误,如果错误为EINTR,说明错误是由中断引起的,如果是ECONNREST表示网络连接出了问题。

  • write:将buf中的nbytes字节内容写入到文件描述符fd,成功时返回写的字节数,失败的时候返回-1;在实际的程序中,写入有两种可能:

    • write的返回值大于0,表示写了部分或者是全部的数据。这样我们用一个while循环来不停的写入,但是循环过程中的buf参数和nbyte参数得由我们来更新。也就是说,网络写函数是不负责将全部数据写完之后在返回的。
    • 返回的值小于0,此时出现了错误。我们要根据错误类型来处理.如果错误为EINTR表示在写的时候出现了中断错误。如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接).
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);

第四个参数可以是

flags 描述
MSG_DONTROUTE 不查找表
MSG_OOB 接受或者发送带外数据
MSG_PEEK 查看数据,并不从系统缓冲区移走数据
MSG_WAITALL 等待所有数据

当recv/send的flag参数设置为0时,则和read/write是一样的。
如果有如下几种需求,则read/write无法满足,必须使用recv/send:

  • 为接收和发送进行一些选项设置
  • 从多个客户端中接收报文
  • 发送带外数据(out-of-band data)

TCP客户端

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<netdb.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>

using namespace std;

int main(int argc, char *argv[])
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值