Linux——socket高级通信 select socket选项 Http
来源:互联网 发布:算法 n=n-1 编辑:程序博客网 时间:2024/06/05 05:10
多进程的问题:数据共享。
多进程的问题:进程的上下文环境(context)不能共享
文件描述符号是整数以及对应上下文环境
多进程的问题:上下文环境共享
一.SELECT TCP服务器编程模式
1.select函数
int select(
int fds,//建议是监控的文件描述符号的最大值+1
fd_set *readfds,//读文件描述符号集合
//该参数既是输入,也是输出
//输入:被监控的描述符号
//输出:有数据的描述符号
fd_set *writefds,//
fd_set *errfds,
struct timeval*timeout);//指定阻塞时间限制
//为NULL,永久
返回:
>0:发生改变的文件描述符号个数
=0:时间限制过期
=-1:异常
2.IO能否发出信号?异步IO就是通过信号工作.
3.应用使用select
select.c
#include <stdio.h>#include <fcntl.h>#include <signal.h>#include <unistd.h>#include <sys/select.h>main(){fd_set fds;int r;char buf[100];while(1){FD_ZERO(&fds);//清空FD_SET(0,&fds);//加入读描述符r=select(1,&fds,0,0,0);printf("有数据输入!\n");r=read(0,buf,99);//只要0不读取 再次循环到select就返回 没有数据就阻塞}}
4.使用select实现TCP的多客户连接与处理
chatServer.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/select.h>main(){int sfd;//服务器描述符号int fdall[100];//客户描述符号int count;//客户个数int r;//返回值(异常处理)struct sockaddr_in dr;//IP地址与端口fd_set fds;//被select监控的描述符号集合int maxfd;//最大文件描述符号int i,j;//循环变量char buf[1024];//客户聊天数据//1.建立socketsfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1) printf("1:%m\n"),exit(-1);printf("socket ok!\n");//2.绑定地址与端口dr.sin_family=AF_INET;dr.sin_port=htons(8866);inet_aton("192.168.1.116",&dr.sin_addr);r=bind(sfd,(struct sockaddr*)&dr,sizeof(dr));if(r==-1) printf("2:%m\n"),close(sfd),exit(-1);printf("bind ok!\n");//3.监听r=listen(sfd,10);if(r==-1) printf("3:%m\n"),close(sfd),exit(-1);printf("listen ok!\n");//初始化count=0;maxfd=0;FD_ZERO(&fds);//清空for(i=0;i<100;i++){fdall[i]=-1;}while(1){//4.构造监听的描述符号集合//4.1.清空FD_ZERO(&fds);maxfd=0;//4.2.加入服务器描述符号(服务器描述符号(有没有客户连接),客户代理描述符号(有无数据发送))FD_SET(sfd,&fds);maxfd=maxfd>=sfd?maxfd:sfd;//4.3.加入客户描述符号for(i=0;i<count;i++){if(fdall[i]!=-1){FD_SET(fdall[i],&fds);maxfd=maxfd>=fdall[i]?maxfd:fdall[i];}}//5.使用select选出改变的描述符号 r=select(maxfd+1,&fds,0,0,0);if(r==-1) { printf("服务器崩溃!\n"); break;}//6.分两种情况处理://6.1.有客户连接:服务器描述符号if(FD_ISSET(sfd,&fds)){fdall[count]=accept(sfd,0,0);if(fdall[count]==-1){ printf("服务器崩溃!\n");//释放所有客户break;}printf("有客户连接!\n");count++;}//6.2.有客户发送数据:客户描述符号for(i=0;i<count;i++){//判定改变描述符号是否存在 if( fdall[i]!=-1 &&FD_ISSET(fdall[i],&fds)){//读取数据r=recv(fdall[i],buf,1023,0);if(r==0){printf("有客户退出!\n");close(fdall[i]);fdall[i]=-1;}if(r==-1){printf("网络故障!\n");close(fdall[i]);fdall[i]=-1;}if(r>0){ //广播数据buf[r]=0;printf("广播数据:%s\n",buf);for(j=0;j<count;j++){if(fdall[j]!=-1){send(fdall[j],buf,r,0);}}}}}}}5.poll模式
int poll(
struct pollfd *fds,//监控的描述符号
int nfds,//监控的描述符号的个数
int timeout ); //阻塞超时
poll.c
#include <stdio.h>#include <fcntl.h>#include <signal.h>#include <unistd.h>#include <sys/poll.h>main(){struct pollfd fds[1];int r;char buf[100];fds[0].fd=0;fds[0].events=POLLIN;while(1){r=poll(fds,1,-1);if(fds[0].revents & POLLIN){printf("有数据输入!\n");r=read(0,buf,99);}}}
二.Socket选项设置
1.socket有哪些选项可以设置 man 7 socket
ARP
|
IP
|
|-----------------|
UDP TCP
通用选项:
SOL_SOCKET 选项
SO_BROADCAST 广播 这些都是选项名
SO_RCVBUF 描述符号的缓冲的大小
SO_SNDBUF 描述符号的缓冲的大小
SO_REUSEADDR 地址反复绑定
SO_TYPE 描述符号类型SOCK_STREAM SOCK_DGRAM?
ICMP选项
IPPTOTO_ICMP
ICMP_FILTER
IP选项(干预系统生成IP头)
IPPROTO_IP
......
......
UDP选项
IPPROTO_UDP
......
TCP选项
IPPROTO_TCP
......
setsockopt设置选项
getsockopt获取选项
int getsockopt(int sockfd,//文件描述符
int level,//哪个选项
int optname,//选项名
void *optval,//返回选项值
socklen_t *optlen);//选项值的长度
案例:
判定一个socket的数据类型AF_INET:SOCK_STREAM SOCK_DGRAM SOCK_RAW
socketopt.c
#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>main(){int fd;int type;int len;len=sizeof(type);fd=socket(AF_INET,SOCK_DGRAM,0);getsockopt(fd,SOL_SOCKET,SO_RCVBUF,&type,&len);//缓冲大小printf("缓冲大小:%u\n",type);/* getsockopt(fd,SOL_SOCKET,SO_TYPE,&type,&len);printf("%u:%u\n",SOCK_STREAM,type);if(type & SOCK_STREAM){printf("流!\n");}if(type & SOCK_DGRAM){printf("报文!\n");}*/}
案例:
使用选项进行数据广播.
cast_A发送
建立socket
设置广播选项
发送数据(广播方式发送)
cast_A.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>main(){int fd;int opt=1;int r;struct sockaddr_in dr;//1.选项设置fd=socket(PF_INET,SOCK_DGRAM,0);if(fd==-1) printf("1:%m\n"),exit(-1);r=setsockopt(fd,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt));if(r==-1) printf("2:%m\n"),exit(-1);dr.sin_family=AF_INET;dr.sin_port=htons(9999);//2.使用广播IP地址dr.sin_addr.s_addr=inet_addr("192.168.1.255");//广播地址r=sendto(fd,"Hello",5,0,(struct sockaddr*)&dr,sizeof(dr));if(fd==-1) printf("3:%m\n");close(fd);}
case_B接收
建立socket
设置地址可重用选项
绑定地址
接收数据
cast_B.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>main(){int fd;int opt=1;char buf[100];int r;struct sockaddr_in dr;fd=socket(PF_INET,SOCK_DGRAM,0);if(fd==-1) printf("1:%m\n"),exit(-1);//1.选项r=setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));if(r==-1) printf("2:%m\n"),exit(-1);dr.sin_family=AF_INET;dr.sin_port=htons(9999);//2.广播地址dr.sin_addr.s_addr=inet_addr("192.168.1.255");r=bind(fd,(struct sockaddr*)&dr,sizeof(dr));if(r==-1) printf("3:%m\n"),exit(-1);r=recv(fd,buf,100,0);//没有信息时会等待if(r>0){buf[r]=0;printf("广播数据:%s\n",buf);}close(fd);}
三.OOB数据(TCP)
优先(带外)数据
send(,MSG_OOB);
recv(,MSG_OOB);
案例:
oob_server.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#include <fcntl.h>int fd,cfd;//要在一个级别void handle(int s){char data[100];int r;if(s==SIGURG){r=recv(cfd,data,100,MSG_OOB);data[r]=0;printf("$$%s\n",data);}}main(){int opt=1;char buf[100];int r;struct sockaddr_in dr;fd=socket(PF_INET,SOCK_STREAM,0);if(fd==-1) printf("1:%m\n"),exit(-1);printf("1\n");dr.sin_family=AF_INET;dr.sin_port=htons(10000);dr.sin_addr.s_addr=inet_addr("192.168.1.116");r=bind(fd,(struct sockaddr*)&dr,sizeof(dr));if(r==-1) printf("2:%m\n"),exit(-1);printf("2\n");r=listen(fd,10);if(r==-1) printf("3:%m\n"),exit(-1);printf("3\n");signal(SIGURG,handle);cfd=accept(fd,0,0);fcntl(cfd,F_SETOWN,getpid());//带外数据将发送信号发送到本进程 默认是系统根进程if(cfd==-1) printf("4:%m\n"),exit(-1);printf("4\n");while(1){r=recv(cfd,buf,100,0/*MSG_OOB*/);//如果接收到带外数据则发送个信号SIGURGif(r>0){buf[r]=0;printf("接收数据:%s\n",buf);}else{break;}}close(cfd);close(fd);}
oob_client.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>main(){int fd;int opt=1;char buf[100];int r;struct sockaddr_in dr;fd_set fds;fd=socket(PF_INET,SOCK_STREAM,0);if(fd==-1) printf("1:%m\n"),exit(-1);printf("1\n");dr.sin_family=AF_INET;dr.sin_port=htons(10000);dr.sin_addr.s_addr=inet_addr("192.168.1.116");r=connect(fd,(struct sockaddr*)&dr,sizeof(dr));if(r==-1) printf("2:%m\n"),exit(-1);while(1){FD_ZERO(&fds);FD_SET(fd,&fds);select(fd+1,0,&fds,0,0);send(fd,"Hello",5,MSG_OOB);//如果频繁往缓冲写 缓冲内容过多而由于 //只有一个带外数据 体现不出sleep(1);}close(fd);}1.OOB数据只能接收/发送成功一个字符
2.普通数据使用一般方式接收与发送,OOB数据使用MSG_OOB接收与发送
3.一个数据使用MSG_OOB,则最后一个是OOB,其他非OOB数据
4.问题:OOB数据是优先数据。优先体现在什么地方?
四.HTTP协议以及应用
1.HTTP协议版本HTTP1.0 HTTP1.1
2.HTTP是应用协议
3.HTTP协议分成:
请求协议 浏览器发给Web服务器的
响应协议 Web服务器发给浏览器的
index.html
<html><head><title>Http Protocol</title></head><body><form action="http://192.168.1.116:10000/index.php" target="_self" method="post">姓名:<input type="text" name="user" value="tom"/><br/>口令:<input type="password" name="pass" value="tom"/><br/><input type="submit" value="登录"/></form></body></html>用浏览器打开这个网页 就向服务器发送信息 服务器就收到以下信息
请求行(请求方法 请求资源 协议版本)
请求体(请求头:请求值)
空行
数据(querystring:key=value&key=value)
http_c.c//类似浏览器功能 服务器会跟据请求给出响应
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>main(){int fd;struct sockaddr_in dr;char strreq[1024];char buf[10*1024];int r; //建立socketfd=socket(AF_INET,SOCK_STREAM,0);//连接服务器192.168.0.72dr.sin_family=AF_INET;dr.sin_port=htons(80);dr.sin_addr.s_addr=inet_addr("192.168.0.72");r=connect(fd,(struct sockaddr*)&dr,sizeof(dr));//构建http请求字符串sprintf(strreq,"GET /index.php HTTP/1.1\r\n""Host: 192.168.0.72:80\r\n""User-Agent: Tarena5.0\r\n""Accept: text/html,image/png\r\n"//浏览器能接收的"Accept-Language: zh-cn\r\n""Accept-Charset: gb2312,utf-8\r\n" "Keep-Alive: 300\r\n" "Connection: keep-alive\r\n" "\r\n"); //发送http请求字符串 r=send(fd,strreq,strlen(strreq),0);//向服务器发送请求 //等待服务器响应 //while(1) //{ r=recv(fd,buf,1024,0);//接收服务器响应//if(r<=0) break;printf("========================\n"); printf("%s\n",buf);printf("========================\n");//} close(fd);}
5.响应协议的格式
响应行(协议版本 响应码 响应码的文本描述)
响应体(响应头: 响应值)
空行
数据(普通数据/分块数据)
http_s.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#include <fcntl.h>#include <string.h>int fd,cfd;main(){char buf[1024];int r;struct sockaddr_in dr;char strres[1024];fd=socket(PF_INET,SOCK_STREAM,0);if(fd==-1) printf("1:%m\n"),exit(-1);printf("1\n");dr.sin_family=AF_INET;dr.sin_port=htons(10000);dr.sin_addr.s_addr=inet_addr("192.168.1.116");r=bind(fd,(struct sockaddr*)&dr,sizeof(dr));if(r==-1) printf("2:%m\n"),exit(-1);printf("2\n");r=listen(fd,10);if(r==-1) printf("3:%m\n"),exit(-1);printf("3\n");cfd=accept(fd,0,0);if(cfd==-1) printf("4:%m\n"),exit(-1);printf("4\n");sprintf(strres,"HTTP/1.1 200 OK\r\n""Server: tarena2.0\r\n""Content-Type: text/html\r\n""Content-Length: 28\r\n""Connection: keep-alive\r\n""\r\n""<font color=red>靓崽!</font>");while(1){r=recv(cfd,buf,1024,0);if(r>0){buf[r]=0;printf("接收数据:%s\n",buf);send(cfd,strres,strlen(strres),0);}else{break;}}close(cfd);close(fd);}
用浏览器访问http://192.168.1.116:10000/index.html
1XX 正在处理
2XX 响应成功200
3XX 继续处理
4XX 客户错误
5XX 服务器错误
实现ifconfig工具
总结:
重点:
select
广播
了解:
OOB数据
HTTP协议
应用:
独立编写TCP服务器端的select模式
编写广播
能够请求一个网页,并且解析响应
作业:
1.把聊天程序使用poll实现
2.使用UDP的广播,发送一个文件
3.随意挑选网站,把主页下载并保存成html文件
- Linux——socket高级通信 select socket选项 Http
- linux ipc—socket通信
- socket通信高级模型
- Linux下网络socket编程——实现服务器(select)与多个客户端通信
- Socket编程基础——Socket选项
- Linux中的socket通信——TCP
- Socket和Http通信
- Socket和Http通信
- socket http通信
- Socket和Http通信
- Socket和Http通信
- Windows Socket select 通信实例
- linux select socket 例子
- linux socket select使用
- select-socket-linux
- Linux Socket Select说明
- [linux C]使用select进行非阻塞socket通信
- Linux下基于select的socket通信 队列回收功能
- 虚拟化技术比较 PV HVM
- seajs+backbone实现单页面应用模块…
- HTTP Status 500 - Handler processing failed; nested exception is java.lang.OutOfMemoryError: PermGen
- 解决cua mode下emacs与系统剪切板不同步问题
- 第一个安卓app【转】
- Linux——socket高级通信 select socket选项 Http
- Android开发之旅:环境搭建及Hello…
- 【云时代,我也来赶赶潮流】玩玩七…
- Android SDK开发包国内下载地址
- 关于拉格朗日对偶问题中对偶性的理解
- 自学安卓,哈哈等着我变大神吧~~~
- 学习路上的第二个项目:安卓二维码
- webview与js交互
- linux top