网络编程——基础1
使用语言——C语言
socket模型创建流程图(TCP)
下图是基于TCP协议的客户端/服务器程序的一般流程:
服务器端的创建:server.c
创建套接字:socket()函数
函数原型:
参数说明:
- domain 是地址族
- type 套接字的类型
SOCK_STREAM 流式套接字
SOCK_DGRAM 数据报套接字
SOCK_RAW 原始套接字 - protocol 参数通常设置为0
协议参数0代码表默认协议(流:TCP,数据报:UDP)
所谓的大小端,大致的解释意思就是:
【大端模式】 CPU对操作数的存放方式是高地址存放低位,低地址存放高位。
【小端模式】CPU对操作数的存放方式是高地址存放高位,低地址存放低位。
大多数ARM处理器都是采用的小端模式,PowerPC是采用的大端模式,网络字节序是采用的大端模式。
大小端如何相互转化
(主机字节序转化为网络字节序)
主机字节序与网络字节序
字节序:指整数在内存中的保存顺序
网络字节序: 网络字节序将数据的重要部分保存在低地址,不重要的部分保存到高地址,即低地址保存的是数据的高字节位,高地址保存的是数据的低字节位。在网络编程时用到的IP地址和端口号都需要网络字节序。
本地字节序:对于Inter x86处理器来说,将数据的不重要的部分保存在低地址,重要的部分保存在高地址,即低地址中保存的是数据的低字节位,高地址保存的是数据的高字节位。
绑定套接字:bind()函数
绑定的目的是:使服务器拥有众所周知的固定地址
函数原型:
参数说明:
- sockfd 由socket()调用返回
- addr 是指向sockaddr_in结构的指针,包含本机IP地址和端口号
- addrlen : sizeof(struct sockaddr_in) 表示结构体的大小
表示地址信息的结构体:
struct sockaddr_in addr;
(sockaddr_in网络套接字地址信息、sockaddr_un本地套接字地址信息、sockaddr通用)
创建监听队列:listen()函数
函数原型:
参数说明:
- sockfd 监听需要连接的套接字
- backlog 指定正在等待连接的最大队列长度,它的作用在于处理可能同时出现的几个连接请求。Dos(拒绝服务)攻击即利用了这个原理,非法的连接占用了全部的连接数,造成正常的连接请求被拒绝。
- 返回值 0或者-1
完成listen()调用后,socket完成了监听socket(listening socket)
接收连接请求:accept()函数
函数原型:
- sockfd 监听套接字
- addr 对方地址
- addrlen 地址长度
- 返回值:已建立好连接的套接字或-1
(使用时必须判断是否请求成功)
listen()和accept()函数是TCP服务器端使用的函数
服务器端代码:server.c
int main(){
int listenfd,connfd;
//创建监听套接字
listenfd = socket(AF_INET,SOCK_STREAM,0);
if(listenfd<0){
perror("socket");
exit(EXIT_FAILURE);
}
//给套接字绑定地址(需要用结构体来表示地址信息)
struct sockaddr_in addr;
bzero(&addr,sizeof(addr));//memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET; //计算机的ip
addr.sin_port=htons(6677); //端口号
//服务器的ip地址,需要进行字节序的转换
addr.sin_addr.s_addr=htonl(INADDR_ANY);
//开始绑定地址信息
if(bind(listenfd,(struct sockaddr*)&addr,sizeof(addr))<0){
perror("bind");
exit(EXIT_FAILURE);
}
//创建监听队列
listen(listenfd,20);//完成listen调用后,socket完成监听(进入监听状态)
char buf[4096];
int n;
while(1){
printf("server waiting...\n");
//accept从监听队列中取出连接请求
//取出后会创建连接套接字
connfd=accept(listenfd,NULL,NULL);
//从连接套接字中读取数据
n=read(connfd,buf,sizeof(buf));
buf[n] = '\0';
printf("buf = %s\n",buf);
//回射服务器
write(connfd,buf,n);
close(connfd);
}
exit(EXIT_SUCCESS);
}
客户端的创建:
启动连接:connect()函数
函数原型:
参数说明:
- sockfd 客户端socket返回的文件描述符
- addr 服务器端的地址信息
- addrlen 服务器端的地址信息长度
(使用时必须判断是否请求成功)
客户端代码:client.c
int main(){
//创建一个客户端套接字
int sockfd;
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0){
perror("socket");
exit(EXIT_FAILURE);
}
struct sockaddr_in addr;
bzero(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port=htons(6677);
addr.sin_addr.s_addr=inet_addr("127.0.0.1");
if(connect(sockfd,(struct sockaddr*)&addr,sizeof(addr))<0){
perror("connect");
exit(EXIT_FAILURE);
}
write(sockfd,"hello world",strlen("hello world"));
char buf[100];
int n;
n=read(sockfd,buf,sizeof(buf));
buf[n]='\0';
printf("%s\n",buf);
close(sockfd);
exit(EXIT_SUCCESS);
}