从函数接口角度分析: socket其实也是一个函数接口,其作用是申请对应协议的套接字(两台相同协议的主机之间通信的桥梁)。 例如: TCP套接字(TCP socket) = socket(TCP协议); UDP套接字(UDP socket) = socket(UDP协议);
套接字是一个特殊的文件描述符,为什么说是特殊的? 普通文件描述符 = open(); 套接字 = socket(); -> 因为套接字不是通过open得到的,所以说是特殊的文件描述符。
1、什么是IP地址?
1)含义。 例如: "192.168.19.10" --> 这种形态叫点分制。. 每一个IP地址都是32位,如果大家在网络编程中需要使用IP地址,那么就一定要将这32位转化为网络字节。
2、什么是端口号?
如果某一个地址上,有一个进程在通信,假设这个进程内部有多个socket套接字,那么怎么知道跟谁通信呢?
解决方案: 通信时,除了确定IP地址之外,还要确定端口号。
两个进程之间需要通信,除了IP地址需要在同一个网段之外,还需要有相同的端口号。
主机A ---- 主机B
IP地址: 192.168.19.3 192.168.19.5 --> 必须处于相同网段。(前面三个数字一致,最后一个数字不一样)
端口号: 5000 5000 --> 必须一致。
端口号取值范围: 0~65535 (2的16次方) -> 16位
每一个端口号都是16位,如果大家在网络编程中需要使用端口号,那么就一定要将这16位转化为网络字节。
系统占用了的端口号: 0~1023 (用户不可以使用)
用户有效的端口号: 1024~65535 (用户随便使用) -> 用户使用完端口号之后,由于资源没有释放,至少等待1分钟,才可以再次使用。
网络编程通信协议。
1、什么是通信协议? 两个进程之间使用网络编程来通信之前,必须定义好一个关系。 -> 协议:传输层协议。 主机A使用TCP协议,那么主机B就必须使用TCP协议才可以跟主机A通信。
2、传输层协议有哪些? 分别是TCP协议与UDP协议,两者区别是: TCP协议 --> Tranmission Control Protocol 这种协议特点: 面向于一种有连接的通信。 (打电话) 传输 控制 协议
UDP协议 --> User Data Protocol 这种协议特点: 面向于一种无连接的通信。 (寄信) 用户 数据包 协议
3、使用TCP协议来通信,服务器与客户端的设计流程是如何? 客户端: 一般用于发送数据。
服务器: 一般用于接收数据,然后根据接受到的数据,然后回发对应的内容给客户端。 详细步骤参考: TCP协议的设计流程.jpg
服务器提供自己的IP地址可以使用一个宏: INADDR_ANY 宏的路径在: /usr/include/linux/in.h
/* Address to accept any incoming messages. */
#define INADDR_ANY ((unsigned long int) 0x00000000)
服务器:
#include "head.h"
int main(int argc,char *argv[]) // ./Rose 50002
{
//1. 创建TCP套接字。
int sockfd;
sockfd = socket(AF_INET,SOCK_STREAM,0); //sockfd -> 未连接套接字
//2. 绑定IP地址、端口号、协议到TCP套接字中。
struct sockaddr_in srvaddr;
socklen_t len = sizeof(srvaddr);
bzero(&srvaddr,len);
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(atoi(argv[1]));
srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sockfd,(struct sockaddr *)&srvaddr,len);
//3. 设置铃声。
//sockfd -> 未连接套接字
listen(sockfd,5);
//sockfd -> 监听套接字
//4. 阻塞地坐等对方的连接。
struct sockaddr_in cliaddr;
bzero(&cliaddr,sizeof(cliaddr));
int connfd;
connfd = accept(sockfd,(struct sockaddr *)&cliaddr,&len);
if(connfd > 0)
{
printf("new connection: %s\n",inet_ntoa(cliaddr.sin_addr));
}
//5. 不断从TCP协议中接受数据。
char buf[100];
while(1)
{
bzero(buf,sizeof(buf));
recv(connfd,buf,sizeof(buf),0);
printf("from client:%s",buf);
if(strncmp(buf,"quit",4) == 0)
{
break;
}
}
//6. 挂断电话。
close(connfd);
close(sockfd);
return 0;
}
客户端:
#include "head.h"
int main(int argc,char *argv[]) // ./Jack 192.168.19.5 50001
{
//1. 创建TCP协议套接字。
int sockfd;
sockfd = socket(AF_INET,SOCK_STREAM,0);
//2. 打电话。
struct sockaddr_in srvaddr;
socklen_t len = sizeof(srvaddr);
bzero(&srvaddr,len);
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(atoi(argv[2]));
inet_pton(AF_INET,argv[1],&srvaddr.sin_addr);
int ret = connect(sockfd,(struct sockaddr *)&srvaddr,len);
if(ret == -1)
{
printf("connect error!\n");
}
//3. 不断发送数据给服务器。
char buf[100] = {0};
while(1)
{
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
send(sockfd,buf,strlen(buf),0);
if(strncmp(buf,"quit",4) == 0)
{
break;
}
}
//4. 挂断。
close(sockfd);
return 0;
}
三次握手
1、“三次握手”解析什么问题? 解析基于有连接的TCP协议是如何确定可靠性。
2、三次握手分别做了什么事情? 第一次握手: 客户端会发送syn包(seq=j)给服务器,然后等待服务器确定。
第二次握手: 服务器收到syn包之后,必须确定客户端的syn包(ack=seq+1),同时服务器在给客户端发送一个syn包(seq=k),此时服务器再处于等待的状态。
第三次握手: 客户端收到服务器的syn+ack包之后,向服务器发送确认包ack包(ack=seq+1),此包发送成功之后,客户端与服务器才会进入连接状态。
TCP/IP协议模型。 该模型一共有4层。