步骤:
TCP服务器 TCP客户端
1.建立sock套接字。 1.建立sock套接字
2.绑定IP和端口号。 2.主动连接服务器
3.监听 3.接收/发送
4.等待客户端连接 等电话来
5.接收/发送
TCP服务器搭建
1.建立套接字socket(创建一个具有网络属性的文件描述符)
头文件:#include <sys/types.h>
#include <sys/socket.h>
函数:int socket(int domain, int type, int protocol);
功能:建立sock套接字。
参数:
domain:地址族
domain | |||
AF_UNIX,AF_LOCAL | Local communication | unix(7) | 本地连接协议 |
AF_INET | IPv4 Internet protocols | ip(7) | IPv4协议 |
AF_INET6 | IPv6 Internet protocols | ipv6(7) | IPv6协议 |
type:协议
type | |
SOCK_STREAM | 流式套接字(TCP) |
SOCK_DGRAM | 数据报文套接字(UDP) |
SOCK_RAW | 原始套接字 不选用任何协议 |
protocol:参数生效值
默认为:0 --->前两个参数生效
返回值:成功返回套接字文件描述符,失败返回-1,并设置错误码。
2.绑定IP和端口号bind
(1)绑定端口号
头文件:#include <sys/types.h>
#include <sys/socket.h>
函数:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:将IP和端口号绑定到文件描述符。
参数:
sockfd:套接字文件描述符
addr:struct sockaddr * 赋值的结构体指针
(要换结构体,所以一般用(struct sockaddr *)&server)
addrlen:addr的长度
(直接sizeof(结构体))
返回值:成功返回0,失败返回-1,并设置错误码。
结构体:
struct sockaddr {
sa_family_t sa_family; //地址族 u short
char sa_data[14]; //IP和端口号
}----->16个字节
但是赋值不严谨,所以需要另一个结构体进行IP和端口号赋值
头文件:<netinet/in.h>
结构体sockaddr_in
struct sockaddr_in {
short sin_family; /* Address family */ 地址族
__be16 sin_port; /* Port number */ 大端序端口号
struct in_addr sin_addr; /* Internet address */IP地址
{s_addr} 专门给IPv4地址赋值的
unsigned char sin_zero[8]; /* Same size as struct sockaddr */填充位
};
其中__be16 sin_port为大端序16位
__be16:大端序16位
__le32:小端序32位
所以要把小端序数地址改为大端序
头文件#include <arpa/inet.h>
函数:uint32_t htonl(uint32_t hostlong); //针对32位
uint16_t htons(uint16_t hostshort); //针对16位
前两个:小转大
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
后两个:大转小
(2)IP地址赋值—inet_addr
系统是不会自动帮你把点分十进制转化为网络二进制的所以,我们需要自行获取IP地址的网络二进制,再传入结构体中,server.sin_addr.s_addr
头文件:#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
函数:in_addr_t inet_addr(const char *cp);
功能:将点分十进制转化为网络二进制。
参数:
cp:字符串IP地址,例如(“192.168.60.5”)。
返回值:成功返回二进制地址,失败转化无效,返回INADDR_NONE。
3.监听—listen
用来限制服务器同一时刻接入客户端的最大值。
头文件:#include <sys/types.h>
#include <sys/socket.h>
函数:int listen(int sockfd, int backlog);
功能:监听 :限制服务器同一时刻被连接的最大值。
参数:
sockfd:套接字文件描述符。
backlog:同一时刻被连接的最大值。
返回值:成功返回0,失败返回-1,并设置错误码。
4.等待客户端连接—accept
头文件:#include <sys/types.h>
#include <sys/socket.h>
函数:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:阻塞等待客户端连接,具有阻塞功能。
参数:
sockfd:套接字文件描述符。
addr:保存客户端的IP和端口号的结构体。
addrlen:addr的长度:需要指针( socklen_t len = sizeof(client),函数里用&len )。
返回值:成功返回客户端的fd,失败返回-1,并设置错误码。
5.客户端主动连接服务器—connect
头文件:#include <sys/types.h>
#include <sys/socket.h>
函数:int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:主动连接服务器。
参数:
sockfd: 套接字文件描述符。
addr:服务器的IP和端口号结构体。
addrlen:结构体的大小。
返回值:成功返回0,失败返回-1,并设置错误码。
6.服务器接收数据—recv
头文件:#include <sys/types.h>
#include <sys/socket.h>
函数:ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:接收数据。
参数:
sockfd:数据来源,accept返回的文件描述符。
buf:数据存放的地方。
len:buf的长度。
flags:0阻塞。
返回值:成功返回接收的字节数,失败返回-1,并设置错误码如果断开连接返回0。
7.客户端发送数据—send
头文件:#include <sys/types.h>
#include <sys/socket.h>
函数:ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:发送数据。
参数:
sockfd:给谁发
buf:数据存放的地方
len:buf的长度
flags:0 阻塞
返回值:成功返回发送的字节数,失败返回-1,并设置错误码。
7.双向收发注意事项
服务器从给客户端开的fd里收发数据,客户端从套接字sockfd里收发数据。