首页 > 代码库 > socket api- c/s模式:服务写,客户读. IO模式:阻塞
socket api- c/s模式:服务写,客户读. IO模式:阻塞
场景:
1)客户端从服务端获取信息.
2)阻塞模式.
所以:
1)服务端,步骤,socket, addr,bind,listen, loop{accept,write,close(auto socket)},close server socket.
1.1.服务端地址必须绑定,以提供服务.
1.2.listen之后,每个客户端connect会导致加入服务端的listen队列的队尾.
1.3.accpet,时,会从listen队列的队头取出客户address,内核并在服务端建立一个新的自动地址的socket,和客户端连接.
1.4,我们利用内核建立socket,就可以向客户端发送数据.
1.5.记得每次 accept,write,之后,必须关闭此socket,因为是阻塞模式.客户端当没有数据时,会阻塞.也就是线程会挂起,而系统会不时,唤醒这个线程.无数据再次阻塞,挂起.
所以,如果服务端,不关闭的话,就算没有了数据,客户还是会阻塞在 这条语句,statusFlag=read(socketClientFD,buff,10);
并不像,man 2 read.的解释那样.没有数据会返回0.
2)客户端,步骤:socket,connect ,loop(read)
2.1 客户端直接建立socket.地址用内核默认提供的.
2.2. peer 端,必须填写服务的地址.以便连接.
2.3 loop读取一定的数据.因为服务端发送完数据,会主动close.所以客户端在read的时候,当没有数据,可以获得0 状态符.
缺陷:服务端,循环读取 listen 队列,非常耗费资源. 最优是,队列有插入时,应该由内核通知程序.
:服务端采用后台线程来处理客户链接.但是并没有显示关闭此线程(应该主线程关闭后,socket关闭后,后台线程会报错,直接退出吧)
知识点:
1) inet_pton(AF_INET,"127.0.0.1",&serverAddr.sin_addr); 转换后的格式是 4个字节, 是按顺序存放,比如这里是 0x7f,0,0,1
2) serverAddr.sin_port=htons(3003); 因为系统和网络对于数值的存放顺序不同,port是2字节,所以必须用函数转换为大端字序.
3)地址应该就不用转换,因为是4个字节,而每个字节都是是单独的数值,不会有多个字节组合为一个数值的问题.刚开始,老想的头痛,应该是不用转换的.
客户端和服务端用inet_pton就好了.
暂未分析点:
至于 serverAddr.sin_addr.s_addr=htonl(INADDR_ANY); 还没有分析为什么这样写.
server:
#include <iostream> #include <sys/socket.h>//{socket_type.h}:socket,AF_INET,SOCK_STREAM,PF_INET #include <netdb.h>//{<netinet/in.h>}:IPPROTO_TCP #include <sys/errno.h> #include <string.h> #include <stdio.h>//perror #include <fcntl.h> #include <unistd.h>//close. #include <time.h> #include <thread> using namespace std; typedef struct sockaddr_in SA; void Accpetthread(int serverFD); int main() { //socket->addr->bind->listen->accept(get time) int serverFD; int intflag; SA serverAddr; bzero(&serverAddr,sizeof(serverAddr)); serverFD=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); if(serverFD==-1) { perror("create()"); return -1; } serverAddr.sin_addr.s_addr=htonl(INADDR_ANY); serverAddr.sin_family=AF_INET; serverAddr.sin_port=htons(3003); //serverAddr.sin_zero?? intflag=bind(serverFD,(sockaddr*)&serverAddr,sizeof(sockaddr)); if(intflag==-1) { perror("bind()"); return -1; } listen(serverFD,10);//max queue? thread a=thread(Accpetthread,serverFD); a.detach(); int cmd; cout<<"exist:input 88"<<endl; for(;;) { cin>>cmd; if(cmd==88) { break; } } close(serverFD); return 0; } void Accpetthread(int serverFD) { for(;;) { int clientFD=accept(serverFD,0,0); char buff[]="hi,i am server"; write(clientFD,buff,sizeof(buff)); close(clientFD); } }
client:
#include <iostream> #include <sys/socket.h>//{socket_type.h}:socket,AF_INET,SOCK_STREAM,PF_INET #include <netdb.h>//{<netinet/in.h>}:IPPROTO_TCP #include <sys/errno.h> #include <string.h> #include <stdio.h>//perror #include <fcntl.h> #include <unistd.h>//close. #include <time.h> #include <netinet/in.h> #include<arpa/inet.h>//INET_PTON using namespace std; int main() { //socket->connect->read. int socketClientFD; int statusFlag; socketClientFD=socket(PF_INET,SOCK_STREAM,IPPROTO_IP); if(socketClientFD==-1) { perror("socket()"); return -1; } struct sockaddr_in serverAddr; bzero(&serverAddr,sizeof(serverAddr)); serverAddr.sin_family=AF_INET; inet_pton(AF_INET,"127.0.0.1",&serverAddr.sin_addr); serverAddr.sin_port=htons(3003); statusFlag=connect(socketClientFD,(sockaddr*)&serverAddr,sizeof(serverAddr)); if(statusFlag==-1) { perror("connect()"); return -1; } char buff[11]; for(;;) { statusFlag=read(socketClientFD,buff,10); if(statusFlag>0) { buff[10]=‘\0‘; cout<<buff<<flush; } else if(statusFlag==0) { cout<<endl; break; } else { perror("read()"); return -1; } } cout<<"eixist:input 88."<<endl; int cmd; while(1) { cin>>cmd; if(cmd==88) { close(socketClientFD); break; } } return 0; }
socket api- c/s模式:服务写,客户读. IO模式:阻塞