linux 下的简单tcp连接主要过程
首先引入的头文件包括
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
1. 生成套接字并绑定信息
首先申请套接字
首先我们如果想要创建一个服务器我们需要一个容器来记录我们的服务器的一些信息
比如:
- 使用哪一个端口进行交互
- 采用什么协议族
- 本机的地址是什么
在linux 下 我们可以使用 struct sockaddr_in结构体来进行保存以上信息
创建并且进行初始化
struct sockaddr_in addr;
初始化
bzero(&addr , sizeof(addr));
进行绑定服务器的信息
1. 绑定协议
addr.sin_family = PF_INET
2. 绑定端口
addr.sin_port = htons(8888);
3. 绑定服务器的地址以便客户端进行访问
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
申请套接字 scoket()
在我们进行了信息的绑定之后,首先我们需要申请一个套接字
功能: 创建一个socket
返回值:
成功 : 返回指向新创建的socket文件的描述符
失败 : 返回 -1
参数:
scoket(domain , type , protocol);
domain: 选择什么协议族
AF_INET: 采用IPV4 地址
AF_INET6: 采用IPV6 地址
type:置顶套接字的类型
1.数据流套接字,2.数据报套接字 3. 原始套接字
protocol: 通常赋值"0"。
实例:
sockfd = scoket(PF_INET, SOCK_STREAM , 0);
if(sockfd == -1)
{
printf("创建失败\n");
exit(0);
}
绑定信息 bind()
功能: 给套接字绑定信息
失败返回 -1
使用方法:
ret = bind(sockfd , (struct sin_addr *) &addr , sizeof addr);
if(ret == -1)
{
printf("绑定错误\n");
}
监听客户端 listen()
函数形式
int listen(int sockfd , int backlog);
listen 函数的主要作用十将套接字(sockfd)编程被动的连接监听套接字
(被动等待客户端的连接),参数backlog 的作用是设置内核中连接队列的长度
可见listen的主要作用更像是告诉内核 我是一个服务器!,并且提供一些相应的信息
阻塞队列 accept()
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
常用形式:
int connfd = accept(sockfd , NULL , NULL);
accept() 系统调用主要用在服务器端,即监听的套接字端,它提取出来所监听的套接字等待连接队列中的第一个连接请求,创建一个新的套接字,并返回指向该套接字得文件描述符。
一般来说,实现时accept()为阻塞函数,当监听socket调用accept()时,它先到自己的receive_buf中查看是否有连接数据包;
若有,把数据拷贝出来,删掉接收到的数据包,创建新的socket与客户发来的地址建立连接;
若没有,就阻塞等待.
客户端请求连接 connect()
connect()函数:是一个阻塞函数,建立连接是通过三次握手,而这个连接得过程是由内核完成得,不是这个函数完成,这个函数得作用仅仅通知linux 内核,让linux内核自动完成 TCP 三次握手连接,最后把连接得结果返回给这个函数得返回值
成功返回 : 0
失败 : -1
int ret = connect(sockfd , (struct sockaddr *)&sevaddr,sizeof(sevaddr));
发送函数 send()
将写在data中得数据发送给服务器端
send(sockfd , data , sizeof data , 0);
接受函数 recv()
int ret = recv(connfd , buf , sizeof buf , 0);
将数据读入 buf 中
if(ret <= 0)
{
printf("client quit\n");
break;
}