准备工作
1、本机端口号和网络端口相互转换
uint16_t htons(uint16_t hostshort);//本机 ----》网络
uint16_t ntohs(uint16_t netshort); // 网络 --->本机
2、点分十进制IP 地址 和 网络地址相互转换
int inet_pton(int af, const char *src, void *dst);
函数功能: 将点分十进制地址 转成网络地址
参数说明:
af: 地址族
IPV4: AF_INET
IPV6: AF_INET6
src: ip地址内存的起始地址
dst: 存放网络地址内存的起始地址
const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);
函数功能:将网络地址 转成点分十进制地址 (字符串存储)
参数说明:
af: 地址族
src: 网络地址内存起始地址
dst: 存放点分十进制地址内存的起始地址
size : 内存的大小
地址族结构体: 通过该结构体打包IP和端口号
原始结构体类型(已经不使用!):
struct sockaddr
{
sa_family_t sa_family; /* 地址族 */
char sa_data[14]; /* 地址值,实际可能更长 */
};
改进后的结构体:
struct in_addr
{
in_addr_t s_addr;
};
struct sockaddr_in
{
uint16_t sin_family; //地址族 IPv4: AF_INET
uint16_t sin_port; // 网络字节序端口号
struct in_addr sin_addr; // 网络字节序的IP地址
char sin_zero[8];
};
一、服务端
需要包含的头文件
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include <unistd.h>
一、创建监听套接字
int socket(int domain, int type, int protocol);
参数说明:
domain:地址族
IPV4:AF_INET
IPV6:AF_INET6
type:协议类型
SOCK_STREAM:流式协议
SOCK_DGRAM:报文协议
protoal:0
返回值:成功返回新的套接字;
失败返回-1;
二、绑定地址和端口号
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
参数说明:
sockfd:监听描述符
addr:打包网络字节序地址和端口号结构体变量的地址
addrlen:结构体长度
返回值:成功返回0,失败返回-1
三、通知内核监听套接字
int listen(int sockfd, int backlog);
参数说明:
sockfd:监听描述符
backlog:设置监听队列的长度
返回值:成功返回0,失败返回-1
四、等待接收客户端
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数说明:
sockfd:监听描述符
addr:通用地址结构体变量地址,(保存请求链接客户端的IP和端口号)
addrlen:保存结构体长度变量的地址
返回值:成功返回新的套接字,专门和对应的客户端通讯(全双工)
失败返回-1
ps:accept是一个阻塞函数,如果没有客户端请求链接,会一直阻塞等待。一旦有客户端链接,解除阻塞接收客户端。
二、客户端
一、创建监听套接字
int socket(int domain, int type, int protocol);
参数说明:
domain:地址族
IPV4:AF_INET
IPV6:AF_INET6
type:协议类型
SOCK_STREAM:流式协议
SOCK_DGRAM:报文协议
protoal:0
返回值:成功返回新的套接字;
失败返回-1;
二、请求链接
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数说明:
sockfd:套接字
addr:存放服务器端地址和端口号的地址族结构体变量地址
addrlen:结构体长度
返回值:成功返回0,失败返回-1
然后就是客户端和服务端的通讯使用read和write就行。
其中服务端可能退出时不能再进入我们可以使用下面这条代码对端口进行一个复用操作
//设置套接字端口复用
int opt=1;
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));