Linux下Socket网络通信

头文件:

1
2
3
4
#include <netinet/in.h>
#include <arpa/inet.h> //包含了<sys/socket.h> <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

1、创建socket,返回fd

Socket 函数的原型:int socket(int domain, int type, int protocol);

  • domain :协议族
  • type:通信过程中使用的协议类型 SOCK_STREAM : 流式协议
  • protocol:具体的一个协议,一般写0

    - SOCK_STREAM : 流式协议默认使用 TCP

    - SOCK_DGRAM : 报式协议默认使用 UDP

  • 返回值:

​ - 成功:返回文件描述符。

​ - 失败:-1

1
int fd = socket(AF_INET, SOCK_STREAM, 0);

表明 socket 连接使用的是 Ipv4 协议,套接口的类型为字节流套接口。

2、Socket地址结构体

1
2
3
4
5
6
7
8
9
10
struct sockaddr_in
{
sa_family_t sin_family; //地址族:AF_INET
u_int16_t sin_port; //端口号,要用网络字节序表示
struct in_addr sin_addr; //IPV4地址结构体
}
struct in_addr
{
u_int32_t s_addr; //ipv4地址,要用网络字节序表示
}

服务端代码:

1
2
3
4
5
6
 sockaddr_in ServerAddress;
memset(&ServerAddress, 0, sizeof(sockaddr_in)); //整个结构体清零
ServerAddress.sin_family = AF_INET;
ServerAddress.sin_addr.s_addr = htonl(INADDR_ANY); // INADDR_ANY自动获取当前网卡上有效ip
//ip地址,主机字节序转换为网络字节序
ServerAddress.sin_port = htons(4000); //端口号,主机字节序转换为网络字节序

客户端代码:

1
2
3
sockaddr_in ServerAddress;
memset(&ServerAddress, 0, sizeof(sockaddr_in));
ServerAddress.sin_family = AF_INET;

3、bind()

功能:将fd 和本地的IP + 端口进行绑定

函数原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

  • sockfd:通过socket函数得到的fd。

  • addr:需要绑定的地址,把sockaddr_in指针强行转换成sockaddr*。

    (sockaddr_in加入了最后的一个空字符串,使得两个大小对齐,从而可以直接当作sockaddr用)

  • socklen_t:sizeof(struct sockaddr)即第二个参数结构体占的内存大小,unsigned int类型。

4、listen()

原型:int listen(int sockfd, int backlog)

  • sockfd:通过socket函数得到的fd。

  • backlog : TCP 一次性处理连接的队列长度。未连接的和已经连接的和的最大值

  • listen 函数在运行中要维护两个队列:未完成连接队列和已完成连接队列。

5、accept()

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

  • sockfd:用于监听的cfd

  • addr:传出参数,记录了连接成功后客户端的地址信息(ip,port)

  • addrlen : 指定第二个参数的对应的内存大小

  • 返回值:

    - 成功 :用于通信的文件描述符

    - 失败 :-1

  • 阻塞函数,阻塞等待客户端连接

  • 调用一次连接一次

6、connect()

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

  • sockfd: 客户端创建的通信cfd

  • addr : 客户端要连接的服务器的地址信息

  • addrlen : 指定第二个参数的对应的内存大小

  • 调用connect()函数后,客户端进程会自动随机绑定一个端口,也可以自己写一个bind

7、read()/recv()

1
ssize_t read(int sockfd, void *buf, size_t size);

8、write()/send()

1
ssize_t write(int fd, const void *buf, size_t len);