一、网络数据传递流程
1、数据发送流程图
2、下层为是上层的服务是有限制的,如果上层想获取更多的服务只能通过自己去获取,上层服务没有权限要求下层服务提供更多的服务。
二、网络编程
1、在网络编程上有两个角色:服务器 、 客户端。
服务器:作为一个中间桥梁去完成两个客户端的通信。
客户端:作为普通用户使用的应用程序(QQ、游戏、浏览器...)
服务器也不绝对就只是服务器,比如QQ登陆链接以后申请的东西服务器没有,此时服务器就会作为一个客户端去向其他的服务器申请。
定义:在一次通讯中,提供(链接、数据)服务的为服务器;获取(接收)数据的为客户端。
2、网络通讯时协议的选择
传输层TCP协议的特点:面向连接 可靠 数据流服务
传输层UDP协议的特点:无连接 不可靠 数据报服务
那么根据他们的特点应该如何选择呢?
(1)如果通讯是一段时间内持续性的则选择面向连接的;如果是间断性的则选择无连接的。
区别:TCP面向连接:服务器和客户端要进行通讯会在服务器和客户端之间维护一条专有的线路,第一次发起数据后,这个线路就会保留下来以供以后数据的发送,会节省时间
UDP无连接:每一次发送都要重新去寻找线路,比较费时间。 内核维护线路需要付出代价,所以间断性发送数据维护的效率太低。
(2)对于比较关键的数据必须用TCP;对于无关紧要的数据就可以用UDP;
可靠:发送的数据的正确性、准时性、准确性。不可靠的协议成本低、代价小。
3、TCP的编程流程 【至少有两个进程(客户端、服务器)】
(1)服务器代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
void main()
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0); //AF_INET :IPv4 SOCK_STREAM:TCP 协议;
assert(sockfd != -1); //成功返回大于0的值,失败返回-1;
struct sockaddr_in ser, cli;
ser.sin_family = AF_INET; // 地址簇
ser.sin_port = htons(6000); //端口号(>5000的整数值,避免重复)
ser.sin_addr.s_addr =inet_addr("192.168.1.120"); //sin_addr是一个结构体
int res = bind(sockfd, (struct sockaddr*)&ser, sizeof(ser)); //sockaddr_in的地址和长度
assert(res != -1);//崩溃原因:IP地址不对,和主机不匹配; 端口号不对:正在被用(>1024);没有权限(<1024)
listen(sockfd, 5);
printf("listen over\n");
while(1) //实际上只要连接成功,一般不会断开,所以需要在获取监听队列加入循环
{
int len = sizeof(cli);
int c = accept(sockfd, (struct sockaddr*)&cli, &len); //sockfd只是做一个链接 //c是套接字的监听队列
assert(c != -1);
char buff[128] = {0};
recv(c, buff, 127, 0); //从c中获取127个放在buff中
printf("recv:: %s\n", buff);
send(c, "I Know", strlen("I Know"), 0); //回复c
close(c);//关闭链接
}
(2)客户端代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
void main()
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);//创建一个采用tcp协议的套接字
assert(sockfd != -1);
struct sockaddr_in ser, cli;
ser.sin_family = AF_INET;
ser.sin_port = htons(6000); //端口号
ser.sin_addr.s_addr = inet_addr("192.168.1.120"); //将点分十进制转化为整形
int res = connect(sockfd, (struct sockaddr*)&ser, sizeof(ser));
assert(res != -1);
send(sockfd, "hello world", strlen("hello world"), 0); //客户端先send
char buff[128] = {0};
recv(sockfd, buff, 127, 0); //服务器回馈
printf("recv:: %s\n", buff);
close(sockfd); //关闭套接字
}
结果:
循环之后只能强制结束,接着再执行服务器端会崩溃,因为端口号显示还在被占用,只有等待。