注;
·从标准输入读数据,读取了之后,发给缓存区,由服务器处理之后,收到了响应。
简单的TCP 网络程序
--TCP 服务器
·服务器端得作用是接收client 的请求,并进行简单的数据通信
IP地址,端口号,网络字节序等网络编程中的基本概念
--IP地址
·IP地址实在IP协议中,用来标识不同主机的地址
·IP协议默认为IPv4,ip地址是4个字节,32位的整数。
·通常使用点分十进制的字符串表示IP地址,例如192.168.01;用点分割的每一个数字表示一个字节,范围是0-255
·在IP数据包头部中,有两个IP地址,源IP地址和目的IP地址。
--端口号
·是传输层协议的内容,是一个2字节16位的整数。
·端口号是用来标识一个进程,告诉操作系统,当前的这个数据要交给哪一个进程来处理。
·IP地址+端口号能够标识网络上的某一台主机的某一个进程,一个端口号只能被一个进程占用。
·端口号和进程id之间的关系:一个进程可以绑定多个端口号,但是一个端口号只能标识一个进程
·传输层协议的数据段有两个端口号,分别叫做源端口号和目的端口号,在描述“数据是谁发的,发给谁”
--TCP协议
·传输层协议,有连接,可靠传输,面向字节流
--UDP 协议
·传输层协议,无连接,不可靠传输,面向数据报
--网络字节序
·内存中的多字节数据,磁盘文件中的多字节数据相对于文件,网络数据流都有大小端之分。
·发送主机通常将发送缓冲区的数据按内存的地址从低到高的顺序发出
·接受主机把从网络接到的字节依次保存在接受缓冲区中,也是按内存地址从低到高的顺序
·先发出的数据时低地址,后发出的是高地址
·TCP/IP协议规定,网络数据流应该采用大端字节序(如果是小端,要将数据先转换为大端)低地址高字节
例:0x1234abcd写入以0x0000的内存中,
0x0000 0x12
0x0001 0x34
0x0002 0xab
0x0003 0xcd
socket API
--常见的API
·创建文件描述符(TCP/DUP,客户端+服务器)
int socket
·绑定端口号(TCP/UDP,服务器)
Int bind
·开始监听(TCP,服务器)
Int listen
·接受请求(TCP,服务器)
Int accept
·建立连接(TCP,客户端)
Int connect
·socket API是一种抽象的网络编程接口,适用于各种底层网络协议,各种网络协议的地址格式不同
·socketAPI 的接口是sockaddr,但是在基于IPV4 编程时,使用的数据结构是socketaddr_in 这个结构主要有三部分:地址类型,端口号,IP地址
·案例:简单的UDP网络程序
struct sockaddr
{
_SOCKADDR_COMMON(sa_);
char sa_data[14];
};
struct sockaddr_in//环形IP
{
_SOCKADDR_COMMON (sin_);
in_port_t sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[sizeof(struct sockaddr)-
_SOCKADDR_COMMON_SIZE-
sizeof(in_port_t)-
sizeof(struct in_addr)];
};
//IP地址,用来表示IPv4 的IP地址,其实就是一个32位的整数
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
3,简单的UDP 网络程序
注:
·buf为缓冲区首地址,
·(struct sockaddr*)&client 表示通过socket读到的请求放到哪个缓冲区里
·inet_ntoa(client.sin_sddr)表示转成点分十进制,
·ntohs(client.sin_port),转为网络序
·sendto 和recvfrom 来进行数据读写
--UDP客户端
注;
·从标准输入读数据,读取了之后,发给缓存区,由服务器处理之后,收到了响应。
简单的TCP 网络程序
--TCP 服务器
·服务器端得作用是接收client 的请求,并进行简单的数据通信
注:
·listen(sock,_BACKLOG_)
_BACKLOG_表示的是可等待的个数
·printf("bind and listen success\n");
这句话说明初始化的过程已经完成,可以开始进行通信了
·while(1)
{
socklen_t len=0;
int new_sock=accept(sock,(struct sockaddr*)&client_socket,&len);
if(new_sock<0)
{
printf("new_sock errror\n");
close(sock);
return 3;
}
]
循环的处理连接通过accept把内核中已经建立好的连接拿到用户空间代码中进行处理。
·accept(sock,(struct sockaddr*)&client_socket,&len);
对于TCP 来说,读到EOF
三次握手成功后,服务器调用accept()接受连接
--TCP客户端
·connect(sock,(struct sockaddr*)&server_sock,sizeof(server_sock));
参数必须要是对方的地址和大小,因为要连接的就是对方的
· write(sock,buf,sizeof(buf));
将数据发送给服务器
·客户端一般不允许调用bind,因为在服务器已经调用的前提下,如果客户端也绑定,就会出现同一台主机启动多个客户端,可能出现端口号被占用导致不能正确的连接。
·而服务器也不是必须调用,但是如果不调用,内核会自动给服务器分配监听端口,每次在启动时端口号都不同,所以客户端连接时会出现问题
多进程多线程的简单TCP 网络协议
--多进程
·以上的都是之启用了一个客户端,在同时启用两个或者两个以上的客户端时,在尝试连接服务器时,不能正确的和服务器进行通信
·原因:在accept请求之后,接收了来自客户端的请求,但是又出现了第二个,就会循环尝试read,没有再用到accept,所以只接受了一个请求,无法接收新的请求。
TCP协议通讯流程
服务器初始化
--调用socket,创建文件描述符;
--调用bind。将当前的文件描述符和IP/port绑定在一起;如果这个端口已经被其他的占用了,就会bind失败。
--调用listen,声明当前这个文件描述符作为一个服务器的文件描述符,为后面的accept做好了准备。
--调用accept,并阻塞,等待客户端连接过来。
建立连接的过程(三次握手)
--调用socket,创建文件描述符。
--调用connect,向服务器发起连接请求。
--connect会发出SYN段并阻塞等待服务器应答(第一次)
--服务器收到客户端的SYN,会应答一个SYN-ACK段表示“同意建立连接”;(第二次)
--客户端收到SYN-ACK后会从connect()返回,同时应答一个ACK 段(第三次)
数据传输过程
--建立连接之后,TCP 协议提供全双工的通信服务(在同一条连接中,同一时刻,通信双方可以同时写数据);而半双工只能有一方来写数据
--服务器从accpet ()返回后立刻调用read,读socket就像读管道一样,如果没有数据到达就阻塞等待
--客户端调用write发送请求给服务器,服务器收到之后,对客户端的请求进行处理,在此期间客户端调用read阻塞等待服务器的应答。
--服务器调用write将处理结果发回给客户端,再次调用read阻塞等待下一条请求。
--客户端收到后从read返回,发送下一条请求,如此循环下去
断开连接的过程(四次挥手)
--如果客户端没有更多的请求,就调用close关闭连接,客户端会向服务器发送FIN 段(第一次)
--此时服务器收到FIN 之后,会回应一个ACK,同时read返回0;(第二次)
--read返回之后,服务器就知道客户端关闭了连接,也调用close关闭连接,这个时候服务器会向客户端发送一个FIN (第三次)
--客户端收到FIN,再返回一个ACK 给服务器(第四次)
网络套接字
最新推荐文章于 2024-02-22 07:10:56 发布