Linux系统编程——网络编程(二)Socket编程步骤 和 Linux提供的API解析

227 阅读6分钟

一、Socket编程步骤

TCP服务器编程步骤:

1、创建Socket套接字,用Socket ()函数

2、设置Socket属性,用setsockopt()也可以不用

3、为套接字添加信息(IP地址和端口号)用bind()函数

4、开启监听,用listen()函数

5、监听到有客户端接入,接受一个连接,用accept()函数

6、交换数据,用函数send()和recv(),或者用read(),write()

7、关闭套接字,断开连接

TCP客户端编程步骤:

1、创建一个Socket,用Socket函数

2、设置Socket属性,用setsockopt()也可以不用

3、连接服务器,用connect()函数

4、交换数据,用函数send()和recv(),或者用read(),write()

5、关闭网络连接

在这里插入图片描述

二、API解析

头文件

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

1、连接协议(Socket函数)

作用: 用于根据指定的地址族、数据类型和协议来分配一个套接口的描述字及其所用的资源的函数

函数原型

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

domain: 指明所使用的协议族,通常为AF_INET 表示互联网协议族(TCP/IP协议族)

常用的domain类型有:

AF_INET IPv4因特网域
AF_INET6 IPv6因特网域
AF UNIX Unix 域
AF ROUTE 路由套接字
AFKEYE 钥套接字
AF UNSPEC 未拖定

type: 指定socket类型。

SOCK_STREAM

TCP: 流式套接字提供可靠的、面向连接的通信流:它使用TCP协议,从而保证了数据传输的正确性和顺序性

SOCK_DGRAM

UDP: 数据报套接字定义了一种无连按的服,数据通过相互独立的报文进行传输, 是无序的,并且不保证是可靠,无差错的。它使用数据报协议UDP。

SOCK_RAW

允许程序使用低层协议,原始科接字允许对底层协议如IP或ICMP进行直接访问,功能强大但使用较为不便,主要用于一些协议的开友。

protocol通常赋值为 0 ,0表示选择type类型对应得默认协议

IPPROTO_TCP :TCP传输协议
IPPTOTO_UDP: UDP 传输协议
IPPROTO_SCTP :STCP传输协议
IPPROTO_TIPC :TIPC传输协议

返回值: 成功时返回非负整数,形如文件描述符,失败返回 -1。

2、地址准备(bind函数)

作用:用于绑定IP地址和端口号到Sockfd

函数原型

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

sockfd: 一个socket描述符,由socket函数调用返回

addr: 是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针,指向要邦定给sockfd的协议地址结构,这个地址结构根据地址创建,socket时的地址协议族的不同而不同。

IPV4对应的是:

struct sockaddr{
	unisgned short as family;	//协议族
	char sa data[14]; //IP+端口
};

但是常用的为

struct sockaddr_in{
	sa_family_t sin_family; //协议族
	in_port t sin_port; //端口号
	struct in_addr sin_addr;//IP地址结构体
	unsigned char sin_zero[8];//填充 没有实际意义,
	//只是为跟sockaddh结构在内存中对齐这样两者才能相互转换
};

addrlen: 第二个参数中结构体的大小,一般用sizeof计算,即sizeof(struct sockaddr_in);

3、监听 (listen函数)

作用: 在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。规定内核为相应套接字排队的最大连接数。

listen函数一般在调用bind之后-调用accept之前调用。

函数原型

int listen(int sockfd, int backlog);

sockfd: socket系统调用返回的服务器端,socket描述符
backlog: 指定在请求队列中允许的最大请求数

4、连接(accept函数)

作用: accept函数由TCP服务器调用,用于从已完成连接队列队头返回下一个已完成连接。如果已完成连接队列为空,那么进程被投入睡眠。

函数原型

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

sockfd: socket系统调用返回的服务器端,socket描述符。
addr: 用来返回已经连接的客户端的协议地址。
addrlen: 客户端地址长度

返回值: 该函数的返回值是一个新的套接字描述符。连接成功后对数据的操作,使用的都是这个新的套接字描述符。

返回值是表示已连接的套接字描述符,而第一个参数是服务器监听接字描述行。一个服务器通常仅仅创建一个监听套接字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建一个已连套接字(表示TCP三次握手已完成),当服务器完成对某个给定客户的服务时,相应的已连接套接字就会被关闭。

5、TCP数据收发(第一套)

这一套函数和文件的读写函数相同

头文件

#include <unistd.h>

函数原型

ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);

write: 将buf中的count个字节写入到文件描述符fd中,成功返回写入的字节数,

read: 从fd中读取count个字节到buf中,返回实际所读的字节数,

6、TCP数据收发(第二套)

(1)发送

将buf中的nbytes个字节写入到socket描述符sockfd中,成功时返回写的字节数。

函数原型

ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);

sockfd: sockfd为已建立好连接的Socket文件描述符

buf: buf指向存放待发送数据的缓冲区

nbytes: 待发送数据的长度

flags: 控制选项,一般为0

(2)接收

从sockfd中读取nbytes个字节到buf中,返回实际所读的的字节数。

函数原型

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

sockfd: sockfd为已建立好连接的文件描述符

buf: buf指向存放待接收数据的缓冲区

nbytes: nbytes为待接收数据的长度

返回值: 函数返回读或写的字节个数,出错则返回-1

其他的网络I/O还有一些函数如:recv() /send()、readv()/witev()、recvmsg()/sendnsg()、recvfrom()/sendto()

7、客户端的连接(connect函数)

作用: 用于绑定之后client端(客户端),与服务器建立连接参数

函数原型:

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

sockfd: 套接字描述符
addr: 指向数据结构sockaddr的指针,其中包括目的端口和IP地址
addrlen: 参数二sockaddr的长度,可以通过sizeof(struct sockaddr)获得

返回值: 成功则返回0,失败返回非0,错误码Error()

8、地址转化API:

(1)字符串转网络

作用: 把字符串形式的”192.168.1.123"转为网络能识别的格式

函数原型:

int inet_aton(const char* straddr,struct in_addr *addrp);

参数描述:
straddr: 输入参数straddr包含ASCII表示的IP地址。
addrp: 输出参数addrp是将要用新的IP地址更新的结构。

返回值: 如果这个函数成功,函数的返回值非零,如果输入地址不正确则会返回零。使用这个函数并没有错误码存放在errno中,所以它的值会被忽略。

(2)网络转字符串

作用: 把网络格式的ip地址转为字符串形式、一个32位网络字节序的二进制IP地址转换成相应的点分十进制的IP地址(返回点分十进制的字符串在静态内存中的指针)。

函数原型

char* inet_ntoa(struct in_ addr inaddr);

inaddr: 输入参数straddr包含ASCII表示的IP地址。

返回的字符串存放在WINDOWS套接口实现所分配的内存中。

返回值:无错误发生,inet_ntoa()返回一个字符指针。否则,返回NULL。其中的数据应在下一个WINDOWS套接口调用前复制出来。