自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Http服務器實現(xiàn)文件上傳與下載(三)

網(wǎng)絡 網(wǎng)絡管理
在前2章的內容基本上已經(jīng)講解了整個的大致流程。在設計Http服務器時,我設計為四層的結構,最底層是網(wǎng)絡傳輸層,就是socket編程。接著一層是請求和響應層,叫做Request和Response。

一、引言

在前2章的內容基本上已經(jīng)講解了整個的大致流程。在設計Http服務器時,我設計為四層的結構,最底層是網(wǎng)絡傳輸層,就是socket編程。接著一層是請求和響應層,叫做Request和Response。在上一層是URL解析流程走向層。最頂層我設計為索引層。這一層主要多文件時對文件進行內存上的索引,加快文件的查找?;蛘呖赡苁瞧渌麅热?。在這一次中也包括了一些瀏覽器顯示的頁面內容。這些都是可以讀者自行添加。

在寫這一章節(jié)時,我不知道該是從上往下講解,還是從下往上講解能讓讀者更加清楚我的設計。在思考中.....,最終選擇從底層的socket層開始講解。如果大家對此還有什么疑問可以查看前兩章的內容。

二、socket編程

在開始封裝的時候,大家可以看看《Unix網(wǎng)路編程》這本書,主要的內容還是在上面,主要的代碼和這本書上的大致一致。在這里我在梳理一下。我不會講解所有的API,客戶端上的API我就不講解了,我只是說一下服務器用到的API。

在開始講解時,我需要說2種套接字。只要是為后面的內容做一下解釋。當我們開始socket編程時,需要創(chuàng)建一個套接字和遠程端進行連接的。在這句話中就包含了2種套接字。一種是監(jiān)聽套接字,一種是連接套接字。比如說監(jiān)聽套接字就是我們宿舍樓下的大爺,而連接套接字就是我們。當有一個連接叫做快遞員到達樓下時,被宿舍樓下大爺發(fā)現(xiàn)了,其實就是監(jiān)聽套接字發(fā)現(xiàn)有連接進來了。然后大爺告訴我們,你的快遞來了,然后我們下樓向快遞員簽字拿快遞,這就是建立了連接。

從上面得知我們需要一個監(jiān)聽套接字,也就是宿舍大爺。創(chuàng)建如下:

int socket(int family,int type,int protocal);

發(fā)現(xiàn)沒有,返回值就是套接字,其實就是一個整數(shù),或者稱為文件描述符。因為在linux下所有的設備都是文件,所以可以用一個唯一的整數(shù)代表某個含義。該返回-1時代表創(chuàng)建套接字失敗。一般我們TCP編程參數(shù)填寫會是listenfd= socket(AF_INET,SOCK_STREAM,0);創(chuàng)建的是流套接字,具體內容可以看上面提到的書籍。

接下來我們需要綁定套接字,為什么?因為我們向系統(tǒng)申請了一個套接字(宿舍大爺)后,可是他還沒有工作地點呢,我們需要為他安排工作地點。工作地點也就是端口,要表示一個唯一的工作地點,計算機需要IP和端口同時制定才能確定唯一。

int bind(int sockfd,const struct sockaddr*myaddr,socklen_t addrlen);

若成功返回0,否則返回-1。第一個參數(shù)代表著剛才創(chuàng)建的套接字listenfd。struct sockaddr是一個通用套接字結構,其實我們傳輸?shù)拇_實struct sockaddr_in{}這樣的結構,需要進行強制轉換,原因是這些API都比較老了,歷史原因造成的,主要是之前沒有void*這個類型。socklen_t就是一個無符號的整數(shù)類型。調用方式一般為

bind(listenfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));

這個serveraddr的填充如下:

bzero(&serveraddr,sizeof(serveraddr));

serveraddr.sin_family=AF_INET;

serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);

serveraddr.sin_port=htons(PORT);

而serveraddr的類型確實struct sockaddr_in;

現(xiàn)在也為宿舍大爺安排了工作地點了,接下來無非就是讓大爺工作了,不然申請過來干什么...

int listen(int sockfd,int backlog);

若成功返回0失敗為-1.第一個套接字還是剛才的監(jiān)聽套接字,backlog這個參數(shù)主要涉及到未完成連接隊列和已完成連接隊列的問題?,F(xiàn)在理解為最大的連接數(shù)即可,具體看上面的書本。

最后一個就是當大爺發(fā)現(xiàn)了快遞員,并確定他的身份后,叫我們下來,這是就是下面的api

int accept(int sockfd,struct sockaddr*chliaddr,socklent_t *addrlen);

成功的話返回連接套接字 ,就是我們自己,否則返回-1。在這三個參數(shù)中第一個還是這個監(jiān)聽套接字listenfd,第二個和第三個可以獲取連接者的身份。來著的IP和端口。

一般如果不用設為NULL。例子如下:

clientlen = sizeof(struct sockaddr_in);

int fd = accept(listenfd,(struct sockaddr *)&clientaddr,&clientlen);

當不為clientlen填寫一個默認值的話,程序會報錯的,盡管這個參數(shù)叫做獲取長度,但是我們要是需要先設置大小。

接下來的就是我們與快遞員通訊了。我們接受快遞員遞給我的快遞,這個行為就是read。就是把內容寫入打自己的存儲空間。

ssize_t read(int sockfd,void*buf,size_t nbyte);

讀取成功返回實際讀取的字節(jié)數(shù),如果返回0表示已經(jīng)輸送完畢,小于0表示輸入錯誤,buf就是自己存放接受到的內容,nbyte表示這個空間的大小。這里記住sockfd現(xiàn)在填寫的是連接套接字,是我們自己,而不是老大爺了。

ssize_t write(int sockfd,const void* buf,size_t nbytes);

該函數(shù)把buf中nbytes字節(jié)內容寫入sockfd套接字,發(fā)送給對方。成功返回實際寫了多少字節(jié),失敗返回-1。

到這里已經(jīng)講完需要用到的API,但是最后兩個read和write有點特殊,因為在一些linux系統(tǒng)中,當系統(tǒng)發(fā)生中斷時,可能會停止read或者write。這是我們需要重新調用該函數(shù)。為了能正確的獲取數(shù)據(jù),需要填寫一些代碼,僅僅的調用這2個函數(shù)是不夠的。

下面就是這個套接字的代碼段。把套接字封裝在一個命名空間為TCP的Socket類中。

頭文件(include/socket.h)

 

1 /*
2 * tcp.h
3 *
4 */
5
6 #ifndef SOCKET_H_
7 #define SOCKET_H_
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include 
14 //#include 
15 namespace TCP{
16 class Socket {
17 public:
18 Socket();
19 ~Socket();
20 int server_socket();
21 int server_listen();
22 int server_accept();
23 int server_bind();
24 void server_init();
25 void getClient(sockaddr_in* caddr);
26 int server_read(int fd,char*recvBuf,ssize_t maxlen);
27 int server_write(int fd,char*sendBuf,ssize_t maxlen);
28 void server_close(int confd) ;
29 private:
30 int __readline(int fd,char*recvBuf,ssize_t maxlen) ;
31 int __writen(int fd,char*sendBuf,ssize_t maxlen) ;
32 int listenfd;
33 int confd;
34 struct sockaddr_in serveraddr;
35 socklen_t serverlen;
36 static const int PORT=80;
37 };
38 }
39 #endif /* SOCKET_H_ */

 

#p#

源文件(src/socket.h)

 

1 #include "socket.h"
2 namespace TCP{
3 Socket::Socket() {
4 }
5 Socket::~Socket() {
6 }
7 int Socket::server_socket() {
8 listenfd= socket(AF_INET,SOCK_STREAM,0);
9 if(listenfd !=-1){
10 std::cout<<"server_socket() ...succeed"<
11 }else{
12 std::cout<<"server_socket() ...failed"<
13 }
14 return listenfd;
15 }
16
17 int Socket::server_listen() {
18 int ret = listen(listenfd,100);
19 if(ret ==0){
20 std::cout<<"server_listen() ...succeed"<
21 }else{
22 std::cout<<"server_listen() ...failed"<
23 }
24 return ret;
25 }
26 void Socket::server_close(int confd) {
27 close(confd);
28 }
29 int Socket::server_accept() {
30 clientlen = sizeof(struct sockaddr_in);
31 int fd = accept(listenfd,(struct sockaddr *)&clientaddr,&clientlen);
32 if(fd !=-1){
33 std::cout<<"server_accept() ...succeed"<
34 }else{
35 std::cout<<"server_accept() ...failed"<
36 }
37 return fd;
38 }
39 int Socket::server_bind() {
40 int ret =bind(listenfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
41 if(ret ==0){
42 std::cout<<"server_bind() ...succeed"<
43 }else{
44 std::cout<<"server_bind() ...failed"<
45 }
46 return ret;
47 }
48 void Socket::server_init() {
49 bzero(&serveraddr,sizeof(serveraddr));
50 serveraddr.sin_family=AF_INET;
51 serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);
52 serveraddr.sin_port=htons(PORT);
53
54 }
55 ssize_t Socket::server_read(int fd,char*recvBuf,ssize_t maxlen) {
56 long long havedreadCount=0;
57 int readCount=0;
58 while(1){
59 readCount = __readline(fd,recvBuf+havedreadCount,maxlen);
60 havedreadCount+=readCount;
61 //std::cout<<"readCount:"<
62 if(readCount==0)//當一行是\r\n時,空行,表示這一次讀完。
63 break;
64 }
65 return 0;
66
67 }
68 ssize_t Socket::server_write(int fd,char*sendBuf,ssize_t maxlen){
69
70 return __writen(fd,sendBuf,maxlen);
71 }
72 int Socket::__writen(int fd,char*sendBuf,ssize_t maxlen){
73 size_t nleft;
74 ssize_t nwritten;
75 const char *ptr;
76 ptr=sendBuf;
77 nleft=maxlen;
78 //int count=0;
79
80 while(nleft>0){
81 if((nwritten=write(fd,ptr,nleft))<=0){
82 if(nwritten<0&& errno==EINTR)
83 nwritten=0;
84 else{
85 return -1;
86 }
87 }
88 nleft-=nwritten;
89 ptr+=nwritten;
90 }
91 return maxlen;
92 }
93 int Socket::__readline(int fd,char*recvBuf,ssize_t maxlen) {
94 ssize_t n,rc;
95 char c,*ptr;
96 ptr=recvBuf;
97 for(n=1;n
98 again:
99 if((rc=read(fd,&c,1))==1){
100 *ptr++=c;
101 //std::cout<
102 if(c=='\n')
103 break;
104 }else if(rc ==0){
105 *ptr=0;
106 return n-1;
107 }else{
108 if(errno ==EINTR)
109 goto again;
110 return -1;
111 }
112 }
113 *ptr=0;
114 if(n==2&&*(ptr-2)=='\r'&&*(ptr-1)=='\n')
115 n=0;
116 return n;
117 }
118 }
責任編輯:何妍 來源: 博客園
相關推薦

2015-10-09 09:41:24

HTTP網(wǎng)絡協(xié)議文件傳輸

2015-10-10 16:46:14

HTTP網(wǎng)絡協(xié)議文件傳輸

2015-09-28 13:39:13

Http網(wǎng)絡協(xié)議HTTP

2015-09-29 09:25:20

HTTP網(wǎng)絡協(xié)議

2020-12-02 11:48:05

TFTP

2019-04-23 10:48:55

HTTPTomcat服務器

2018-10-09 09:28:12

HTTPHTTP協(xié)作服務器

2011-08-18 16:03:34

iPhone上傳圖片

2022-03-01 20:33:50

服務web項目

2020-06-17 21:39:11

HTTP協(xié)議服務器

2010-05-25 13:20:46

http與svn

2017-11-10 08:58:49

Web服務器應用程序

2009-07-03 13:05:47

JSP HTTP服務器

2010-03-22 12:57:46

Java Socket

2009-07-06 17:25:22

JSP HTTP服務器

2018-06-15 10:25:43

Python HTTPFTP服務器

2018-12-06 09:23:33

2019-04-24 15:06:37

Http服務器協(xié)議

2012-03-27 11:08:23

Java

2009-07-06 17:56:12

JSP HTTP服務器
點贊
收藏

51CTO技術棧公眾號