网络传输中文件的上传和下载
使用TCP的方式,在服务器和客户端之间进行文件的传输,传输文件时需要传输文件名,文件内容,设置传输完成的标志,处理出错的信息。
TCP三次握手/四次挥手
while(getchar()!='\n'); ----------- 清除输入缓冲区的垃圾数据
IO多路复用
IO多路复用可以同时监控多个描述符,找出其中"活动的"描述符,所谓活动的就是指可以读/写/错误异常。使用IO多路复用可以使用以下接口。
select poll epoll
select多路复用的实现
1.准备要监控的描述符
...
2.将要监控的描述符放入对应的描述符集合(fd_set)
void FD_CLR(int fd, fd_set *set);//从描述符集合中删除指定的描述符
int FD_ISSET(int fd, fd_set *set);//判断描述符集合中是否有该描述符
void FD_SET(int fd, fd_set *set);//从描述符集合中添加指定的描述符
void FD_ZERO(fd_set *set);//情况描述符集合
3.调用select函数监控对应的描述符集合
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
参数:
nfds - 监控的最大的描述符的值+1
readfds - 传入传出参数,传入要监控的读描述符集合,传出活动的读描述符集合(是否可读)
writefds - 传入传出参数,传入要监控的写描述符集合,传出活动的写描述符集合(是否可写)
exceptfds - 传入传出参数,传入要监控的异常描述符集合,传出活动的异常描述符集合(是否出错)
timeout - 超时时间,不使用使用传NULL
返回值:
成功返回活动的描述符个数,超时返回0,出错返回-1
4.处理活动的描述符
网络超时
在工程开发中一般不设置无限等待,需要考虑到对方无响应的情况,将无限等待改为有限时间等待,网络超时就是等待有限的时间,如果有限时间内对方无响应就不再等待。
(1)多路复用的接口中自带超时处理(select poll epoll)
struct timeval tv;
tv.tv_sec = 3;//3s超时
tv.tv_usec = 0;//us
//select
if(select(maxfd+1, &set, NULL, NULL, &tv)<=0){
printf("timeout!\n");
}
(2)通过socket属性来设置超时(read,recv,recvfrom,accept)
struct timeval tv;
tv.tv_sec = xxx;//s
tv.tv_usec = yyy;//us
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
(3)心跳检测
服务器和客户端在一定的时间间隔内(1s)发送一个代表保持连接的数据,表示客户端在线,如果能收到这个包,表示连接有效。
http通信
http属于应用层的协议,同时方式通过请求,请求分为两类 --------- GET/POST
(1)http请求帧格式
请求行(request line)
请求方法(GET) URL http协版本(HTTP/1.0) 回车换行
消息头部(header)
key:value 回车换行(\r\n)
.....
空行 回车换行(\r\n)
请求正文
......
(2)使用C语言编程访问http的API接口
1.解析域名,得到IP
gethostbyname
2.创建socket连接API的IP和端口
socket
以API服务器的IP和端口构造地址
connect
3.构造http请求
按照http协议的要求构造http请求
4.发送http请求
send
5.读取SPI服务器返回的数据
recv
设置地址重用
//在bind前调用
int val = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
获取Linux本机IP
(1)使用getiifaddrs函数
该函数可以获取当前Linux系统中所有网络硬件的信息,调用该函数会传出一个ifaddrs的链表,链表中每一个节点就代表系统的一个网络硬件,其中有IP信息。
参考代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ifaddrs.h>
#include <sys/ioctl.h>
#include <net/if.h>
struct ifaddrs *ifAddrStruct = NULL;
struct ifaddrs *ifa = NULL;
void *tmpAddrPtr = NULL;
//获取网络硬件信息
int res = getifaddrs(&ifAddrStruct);
if(res==-1){
perror("getifaddrs");
exit(-1);
}
//遍历网络硬件信息
for(ifa=ifAddrStruct; ifa!=NULL; ifa=ifa->ifa_next){
//IPV4信息
if(ifa->ifa_addr->sa_family==AF_INET){
char buf[INET_ADDRSTRLEN] = {};
tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
inet_ntop(AF_INET, tmpAddrPtr, buf, INET_ADDRSTRLEN);
printf("%s ip address %s\n", ifa->ifa_name, buf);
}
}
freeifaddrs(ifAddrStruct);
return 0;
(2)可以使用ioctl去获取套接字的ip信息
先创建一个套接字(socket函数),调用ioctl获取网络硬件信息。
参考代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ifaddrs.h>
#include <sys/ioctl.h>
#include <net/if.h>
struct ifreq ifr[32];
struct ifconf ifc;
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd==-1){
perror("socket");
exit(-1);
}
ifc.ifc_len = sizeof(ifr);
ifc.ifc_buf = (caddr_t)ifr;
//获取系统网络硬件信息
int res = ioctl(sockfd, SIOCGIFCONF, (char *)&ifc);
if(res==-1){
perror("ioctl");
exit(-1);
}
int interface = ifc.ifc_len/sizeof(struct ifreq);
while(interface--){
//获取网络硬件信息中的地址参数
res = ioctl(sockfd, SIOCGIFADDR, (char *)&ifr[interface]);
if(res==-1){
perror("ioctl");
exit(-1);
}
printf("ip:%s\n",inet_ntoa(((struct sockaddr_in *)(&ifr[interface].ifr_addr))->sin_addr));
}
return 0;