標籤:iostream out 固定 logs 模式 style 字元 安全 clu
服務端:socket->address->bind->listen->loop{accpet->read->write->close(auto socket)}->close(listen socket)
1)因為是阻塞模式,所以用戶端沒有關閉的時候,服務端會阻塞在read函數,
2)用戶端發送之後中斷連線。是一個有序的資料片。服務端由核心經過排序片。一定會接收到資料。
而不會因為close的資料先到就以為沒有資料。所以必須理解用戶端的行為。也就是write和close函數。
他們都是發送資料包。是有順序的,seq的。包括connect也是發送資料包。只不過工作由核心處理。
connect,write,close。如果按順序寫。發送的包的seq number是持續增加的。
用戶端:socket->connect->wirte->loop(read)->close(client socket)
1)因為是阻塞模式。服務端的read會阻塞。所以用戶端write之後再read。服務端是一定會接收到資料,再進行下一步發送資料的。
2)而用戶端也是阻塞模式。所以read是一定會等待服務端發來的資料。並等到服務端的close資訊。再完成接收資料步驟。
知識點:
char a[]=“” 會計算字元大小並加入結束符
read 函數,會讀入任何符號,包括結束符號。
snprintf(&buff,n,"",x),實際上的字元大小隻有n-1.會自動加入結束符號。
strlen 來計算實際的字元數量。不會包括結束符號。
1)所以write的時候用strlen確定實際字元大小。
2)read的時候。用一個n大小的char數組接收,並明確read的大小為n-1.方便放滿字元還可以自行加入結束符號。
3)每次讀之前,必須清空char數組,方便下次寫入。
未處理知識點:
1)因為是阻塞模式。服務端沒法確定用戶端不再發送資料。因為用戶端不可能關閉。它還要等待接收資料。
而用戶端不關閉。服務端,會一直阻塞在read函數。
所以本實驗是,客戶固定發送比較小的資料,服務端用較大的緩衝區一次接收完客戶資料。
而不考慮服務端一次接收不完的情況。
是否可以自己加入結束邊界標誌?對。書上好像提到過。應該是這樣處理。
2)如果服務端一次沒有讀完客戶資料。socket裡面還有資料。這個時候發送,是發送正常的?是因為socket有2個緩衝區還是,之前的緩衝區清空了?
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>#include <arpa/inet.h>//INET_PTONusing namespace std;typedef struct sockaddr_in SA;void Accpetthread(int serverFD);int main(){ //socket->addr->bind->listen->accept(read ,write) 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); inet_pton(AF_INET,"127.0.0.1",&serverAddr.sin_addr); serverAddr.sin_family=AF_INET; serverAddr.sin_port=htons(3004); //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);//close 之後,地址不能使用.要等待2ml return 0;}//void Accpetthread(int serverFD){ for(;;) { int serverTempFD=accept(serverFD,0,0); //read char readbuf[51]; int sizeread= read(serverTempFD,readbuf,50); readbuf[sizeread]=‘\0‘;//以免溢出,插入結束符號. char writebuff[100]; bzero(writebuff,100);//以免溢出,全部寫結束符號. int tempsize= snprintf(writebuff,99,"%s:%d",readbuf,strlen(readbuf)); cout<<writebuff<<endl; cout<<strlen(writebuff)<<endl;//為什麼size是100?不是根絕\0決定的嗎? write(serverTempFD,writebuff,strlen(writebuff)); close(serverTempFD); }}
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_PTONusing 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); //printf("%0x,%0x,%0x,%0x",((char*)&serverAddr.sin_addr)[0],((char*)&serverAddr.sin_addr)[1],((char*)&serverAddr.sin_addr)[2],((char*)&serverAddr.sin_addr)[3]); serverAddr.sin_port=htons(3004); statusFlag=connect(socketClientFD,(sockaddr*)&serverAddr,sizeof(serverAddr)); if(statusFlag==-1) { perror("connect()"); return -1; } char buff[11]; char writeChar[16]="hi,i am client.";//一定會加入結束符號.char 大小要比實際字元大1. statusFlag= write(socketClientFD,writeChar,strlen(writeChar));//寫的時候只發送字元。不發送結束符。所以用strlen. if(statusFlag==-1) { perror("write()"); return -1; } for(;;) { //bzero(buff,11);//每次要清空,更安全點。雖然後面已經buff[statusFlag]=‘\0‘; statusFlag=read(socketClientFD,buff,10);//這裡會讀入任何符號。包括結束符號。所以要求寫的時候,不要發送結束符號。因此要求用strlen,確定實際字元。 if(statusFlag>0) { buff[statusFlag]=‘\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模式:阻塞