tcp网络编程
tcp网络编程步骤:
由于tcp传输特点是可靠有连接,那么就有
1.客户端向服务端发送连接请求(SYN),
2.服务端接受请求并向客户端发送(SYN+ACK);
3.客户端向服务端回复ACK表明他知道服务端同意连接。
以上三个步骤就是三次握手。
服务端编程步骤:
1.创建套接字
2.为套接字绑定地址信息
3.监听:开始接受服务端的连接请求
4.获取连接建立成功的新socket
5.发送数据
6.接受数据
1.创建套接字
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
domain:地址域
AF_INET :ipv4协议
type: 套接字类型
SOCK_STREAM 流式套接字
SOCK_DGRAM 数据报套接字
protocol :协议类型
如果是0,则表示默认;流式套接字默认tcp协议,报式套接字默认udp协议
流式套接字: IPPROTO_TCP 6
报式套接字:IPPROTO_UDP 17
如:socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
返回值:成功:套接字描述符
失败:-1
2.为socket绑定地址信息
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数: sockfd: socket描述符
addr :socket绑定的地址
addrlen :地址信息长度
返回值:成功:0(网卡操作那个进程),失败 -1
功能:将参数sockfd和addr绑定在一起,使sockfd这个用于网络通讯的文件描述符监听addr所描述的地址和端口号。
sockaddr结构:
struct sockaddr {
sa_f amily_t sa_family;
char sa_data[14];
}
虽然bind里参数是sockaddr,但是真正在基于IPV4编程时,使用的结构体是sockaddr_in;这个结构体里主要有三部分信息:地址类型,端口号,IP地址。
sockaddr_in在头文件#include<netinet/in.h>或#include<arpa/inet.h>中定义。该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中,如下:
structsockaddr_in{
short sin_family;//AF_INET(地址族)PF_INET(协议族)
unsigned short sin_port;/*Portnumber(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/
struct in_addr sin_addr;//32位IP地址
unsigned char sin_zero[8];//没有实际意义,只是为了跟SOCKADDR结构在内存中对齐*/
};
该结构体中提到的另一个结构体in_addr定义如下,它用来存放32位IP地址:
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
in_addr用来表示一个IPV4的IP地址,其实是一个32位整数。
客户端不推荐手动绑定地址信息 ,因为绑定有可能因为特殊原因失败,但是客户端具体使用哪个地址和端口都可以,只要能把数据发送出去,所以客户端程序不手动绑定地址,直至发送数据时,操作系统检测到socket没有绑定地址,会自动选择合适的地址和端口为socket绑定地址,这种数据一般不会出错。
3.监听(服务端监听后才可以接受客户端连接请求)
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
listen()声明sockfd处于监听状态,并且最多允许backlog个客户端处于连接等待状态,如果接受到更多的连接请求就忽略,一般是5,即代表最大同时并发连接数为5,这个数字并不是tcp