Linux下網路socket程式設計——實現伺服器(select)與多個客戶端通訊
Linux下網路socket程式設計——實現伺服器(select)與多個客戶端通訊
置頂 2017年06月23日 14:44:37 閱讀數:3225 標籤: socket程式設計伺服器與多個客戶端通epoll多路複用C語言網路程式設計 更多
個人分類: socket程式設計
一、關於socket通訊
伺服器端工作流程:
- 呼叫 socket() 函式建立套接字 用 bind() 函式將建立的套接字與服務端IP地址繫結
- 呼叫listen()函式監聽socket() 函式建立的套接字,等待客戶端連線 當客戶端請求到來之後
- 呼叫 accept()函式接受連線請求,返回一個對應於此連線的新的套接字,做好通訊準備
- 呼叫 write()/read() 函式和 send()/recv()函式進行資料的讀寫,通過 accept() 返回的套接字和客戶端進行通訊 關閉socket(close)
客戶端工作流程:
- 呼叫 socket() 函式建立套接字
- 呼叫 connect() 函式連線服務端
- 呼叫write()/read() 函式或者 send()/recv() 函式進行資料的讀寫
- 關閉socket(close)
二、用select實現伺服器端程式設計:
select函式樓主在之前文章中(
<span style="color:#000000"><code><span style="color:#009900">#include <stdio.h></span> <span style="color:#009900">#include <netinet/in.h> <span style="color:#009900">//for souockaddr_in</span></span> <span style="color:#009900">#include <sys/types.h> </span> <span style="color:#009900">#include <sys/socket.h></span> <span style="color:#009900">#include <errno.h></span> <span style="color:#009900">#include <stdlib.h></span> <span style="color:#009900">#include <arpa/inet.h></span> <span style="color:#880000">//for select</span> <span style="color:#009900">#include <sys/time.h></span> <span style="color:#009900">#include <sys/types.h></span> <span style="color:#009900">#include <unistd.h></span> <span style="color:#009900">#include <sys/select.h></span> <span style="color:#009900">#include <strings.h> <span style="color:#009900">//for bzero</span></span> <span style="color:#009900">#include <string.h></span> <span style="color:#009900">#define BUFF_SIZE 1024</span> <span style="color:#009900">#define backlog 7</span> <span style="color:#009900">#define ser_port 11277</span> <span style="color:#009900">#define CLI_NUM 3</span> <span style="color:#000088">int</span> client_fds[CLI_NUM]; <span style="color:#000088">int</span> main(<span style="color:#000088">int</span> agrc,<span style="color:#000088">char</span> **argv) { <span style="color:#000088">int</span> ser_souck_fd; <span style="color:#000088">int</span> i; <span style="color:#000088">char</span> input_message[BUFF_SIZE]; <span style="color:#000088">char</span> resv_message[BUFF_SIZE]; <span style="color:#000088">struct</span> sockaddr_in ser_addr; ser_addr.sin_family= AF_INET; <span style="color:#880000">//IPV4</span> ser_addr.sin_port = htons(ser_port); ser_addr.sin_addr.s_addr = INADDR_ANY; <span style="color:#880000">//指定的是所有地址</span> <span style="color:#880000">//creat socket</span> <span style="color:#000088">if</span>( (ser_souck_fd = socket(AF_INET,SOCK_STREAM,<span style="color:#006666">0</span>)) < <span style="color:#006666">0</span> ) { perror(<span style="color:#009900">"creat failure"</span>); <span style="color:#000088">return</span> -<span style="color:#006666">1</span>; } <span style="color:#880000">//bind soucket</span> <span style="color:#000088">if</span>(bind(ser_souck_fd, (<span style="color:#000088">const</span> <span style="color:#000088">struct</span> sockaddr *)&ser_addr,<span style="color:#000088">sizeof</span>(ser_addr)) < <span style="color:#006666">0</span>) { perror(<span style="color:#009900">"bind failure"</span>); <span style="color:#000088">return</span> -<span style="color:#006666">1</span>; } <span style="color:#880000">//listen</span> <span style="color:#000088">if</span>(listen(ser_souck_fd, backlog) < <span style="color:#006666">0</span>) { perror(<span style="color:#009900">"listen failure"</span>); <span style="color:#000088">return</span> -<span style="color:#006666">1</span>; } <span style="color:#880000">//fd_set</span> fd_set ser_fdset; <span style="color:#000088">int</span> max_fd=<span style="color:#006666">1</span>; <span style="color:#000088">struct</span> timeval mytime; <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"wait for client connnect!\n"</span>); <span style="color:#000088">while</span>(<span style="color:#006666">1</span>) { mytime.tv_sec=<span style="color:#006666">27</span>; mytime.tv_usec=<span style="color:#006666">0</span>; FD_ZERO(&ser_fdset); <span style="color:#880000">//add standard input</span> FD_SET(<span style="color:#006666">0</span>,&ser_fdset); <span style="color:#000088">if</span>(max_fd < <span style="color:#006666">0</span>) { max_fd=<span style="color:#006666">0</span>; } <span style="color:#880000">//add serverce</span> FD_SET(ser_souck_fd,&ser_fdset); <span style="color:#000088">if</span>(max_fd < ser_souck_fd) { max_fd = ser_souck_fd; } <span style="color:#880000">//add client </span> <span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>;i<CLI_NUM;i++) <span style="color:#880000">//用陣列定義多個客戶端fd</span> { <span style="color:#000088">if</span>(client_fds[i]!=<span style="color:#006666">0</span>) { FD_SET(client_fds[i],&ser_fdset); <span style="color:#000088">if</span>(max_fd < client_fds[i]) { max_fd = client_fds[i]; } } } <span style="color:#880000">//select多路複用</span> <span style="color:#000088">int</span> ret = select(max_fd + <span style="color:#006666">1</span>, &ser_fdset, NULL, NULL, &mytime); <span style="color:#000088">if</span>(ret < <span style="color:#006666">0</span>) { perror(<span style="color:#009900">"select failure\n"</span>); <span style="color:#000088">continue</span>; } <span style="color:#000088">else</span> <span style="color:#000088">if</span>(ret == <span style="color:#006666">0</span>) { <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"time out!"</span>); <span style="color:#000088">continue</span>; } <span style="color:#000088">else</span> { <span style="color:#000088">if</span>(FD_ISSET(<span style="color:#006666">0</span>,&ser_fdset)) <span style="color:#880000">//標準輸入是否存在於ser_fdset集合中(也就是說,檢測到輸入時,做如下事情)</span> { <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"send message to"</span>); bzero(input_message,BUFF_SIZE); fgets(input_message,BUFF_SIZE,stdin); <span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>;i<CLI_NUM;i++) { <span style="color:#000088">if</span>(client_fds[i] != <span style="color:#006666">0</span>) { <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"client_fds[%d]=%d\n"</span>, i, client_fds[i]); send(client_fds[i], input_message, BUFF_SIZE, <span style="color:#006666">0</span>); } } } <span style="color:#000088">if</span>(FD_ISSET(ser_souck_fd, &ser_fdset)) { <span style="color:#000088">struct</span> sockaddr_in client_address; socklen_t address_len; <span style="color:#000088">int</span> client_sock_fd = accept(ser_souck_fd,(<span style="color:#000088">struct</span> sockaddr *)&client_address, &address_len); <span style="color:#000088">if</span>(client_sock_fd > <span style="color:#006666">0</span>) { <span style="color:#000088">int</span> flags=-<span style="color:#006666">1</span>; <span style="color:#880000">//一個客戶端到來分配一個fd,CLI_NUM=3,則最多隻能有三個客戶端,超過4以後跳出for迴圈,flags重新被賦值為-1</span> <span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>;i<CLI_NUM;i++) { <span style="color:#000088">if</span>(client_fds[i] == <span style="color:#006666">0</span>) { flags=i; client_fds[i] = client_sock_fd; <span style="color:#000088">break</span>; } } <span style="color:#000088">if</span> (flags >= <span style="color:#006666">0</span>) { <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"new user client[%d] add sucessfully!\n"</span>,flags); } <span style="color:#000088">else</span> <span style="color:#880000">//flags=-1</span> { <span style="color:#000088">char</span> full_message[]=<span style="color:#009900">"the client is full!can't join!\n"</span>; bzero(input_message,BUFF_SIZE); <span style="color:#4f4f4f">strncpy</span>(input_message, full_message,<span style="color:#006666">100</span>); send(client_sock_fd, input_message, BUFF_SIZE, <span style="color:#006666">0</span>); } } } } <span style="color:#880000">//deal with the message</span> <span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>; i<CLI_NUM; i++) { <span style="color:#000088">if</span>(client_fds[i] != <span style="color:#006666">0</span>) { <span style="color:#000088">if</span>(FD_ISSET(client_fds[i],&ser_fdset)) { bzero(resv_message,BUFF_SIZE); <span style="color:#000088">int</span> byte_num=read(client_fds[i],resv_message,BUFF_SIZE); <span style="color:#000088">if</span>(byte_num > <span style="color:#006666">0</span>) { <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"message form client[%d]:%s\n"</span>, i, resv_message); } <span style="color:#000088">else</span> <span style="color:#000088">if</span>(byte_num < <span style="color:#006666">0</span>) { <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"rescessed error!"</span>); } <span style="color:#880000">//某個客戶端退出</span> <span style="color:#000088">else</span> <span style="color:#880000">//cancel fdset and set fd=0</span> { <span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"clien[%d] exit!\n"</span>,i); FD_CLR(client_fds[i], &ser_fdset); client_fds[i] = <span style="color:#006666">0</span>; <span style="color:#880000">// printf("clien[%d] exit!\n",i);</span> <span style="color:#000088">continue</span>; <span style="color:#880000">//這裡如果用break的話一個客戶端退出會造成伺服器也退出。 </span> } } } } } <span style="color:#000088">return</span> <span style="color:#006666">0</span>; } </code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
select實現多路複用,多路複用,顧名思義,就是說各做各的事,標準輸入事件到來,有相關函式處理。伺服器處理伺服器的事件,客戶端到來時有相關函式對其進行處理,通過select遍歷各fd的讀寫情況,就不用擔心阻塞了。
三、用epoll實現客戶端程式設計:
1、客戶端程式(epoll_client.c):
<span style="color:#000000"><code><span style="color:#009900">#include<stdio.h> </span>
<span style="color:#009900">#include<stdlib.h> </span>
<span style="color:#009900">#include<netinet/in.h> </span>
<span style="color:#009900">#include<sys/socket.h> </span>
<span style="color:#009900">#include<arpa/inet.h> </span>
<span style="color:#009900">#include<string.h> </span>
<span style="color:#009900">#include<unistd.h> </span>
<span style="color:#009900">#include <sys/epoll.h></span>
<span style="color:#009900">#include <errno.h></span>
<span style="color:#009900">#include <fcntl.h></span>
<span style="color:#009900">#define BUFFER_SIZE 1024 </span>
<span style="color:#000088">int</span> main(<span style="color:#000088">int</span> argc, <span style="color:#000088">const</span> <span style="color:#000088">char</span> * argv[])
{
<span style="color:#000088">int</span> i,n;
<span style="color:#000088">int</span> connfd,sockfd;
<span style="color:#000088">struct</span> epoll_event ev,events[<span style="color:#006666">20</span>]; <span style="color:#880000">//ev用於註冊事件,陣列用於回傳要處理的事件</span>
<span style="color:#000088">int</span> epfd=epoll_create(<span style="color:#006666">256</span>);<span style="color:#880000">//建立一個epoll的控制代碼,其中256為你epoll所支援的最大控制代碼數</span>
<span style="color:#000088">struct</span> sockaddr_in client_addr;
<span style="color:#000088">struct</span> sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(<span style="color:#006666">11277</span>);
server_addr.sin_addr.s_addr =INADDR_ANY;
bzero(&(server_addr.sin_zero), <span style="color:#006666">8</span>);
<span style="color:#000088">int</span> server_sock_fd = socket(AF_INET, SOCK_STREAM, <span style="color:#006666">0</span>);
ev.data.fd=server_sock_fd;<span style="color:#880000">//設定與要處理的事件相關的檔案描述符</span>
ev.events=EPOLLIN|EPOLLET;<span style="color:#880000">//設定要處理的事件型別</span>
epoll_ctl(epfd,EPOLL_CTL_ADD,server_sock_fd,&ev);<span style="color:#880000">//註冊epoll事件</span>
<span style="color:#000088">if</span>(server_sock_fd == -<span style="color:#006666">1</span>)
{
perror(<span style="color:#009900">"socket error"</span>);
<span style="color:#000088">return</span> <span style="color:#006666">1</span>;
}
<span style="color:#000088">char</span> recv_msg[BUFFER_SIZE];
<span style="color:#000088">char</span> input_msg[BUFFER_SIZE];
<span style="color:#000088">if</span>(connect(server_sock_fd, (<span style="color:#000088">struct</span> sockaddr *)&server_addr, <span style="color:#000088">sizeof</span>(<span style="color:#000088">struct</span> sockaddr_in)) == <span style="color:#006666">0</span>)
{
<span style="color:#000088">for</span>(;;)
{
<span style="color:#000088">int</span> nfds=epoll_wait(epfd,events,<span style="color:#006666">20</span>,<span style="color:#006666">500</span>);<span style="color:#880000">//等待epoll事件的發生</span>
<span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>;i<nfds;++i)
{
<span style="color:#000088">if</span>(events[i].events&EPOLLOUT) <span style="color:#880000">//有資料傳送,寫socket</span>
{
bzero(input_msg, BUFFER_SIZE);
fgets(input_msg, BUFFER_SIZE, stdin);
sockfd = events[i].data.fd;
write(sockfd, recv_msg, n);
ev.data.fd=sockfd;
ev.events=EPOLLIN|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);
}
<span style="color:#000088">else</span> <span style="color:#000088">if</span>(events[i].events&EPOLLIN)<span style="color:#880000">//有資料到來,讀socket</span>
{
bzero(recv_msg, BUFFER_SIZE);
<span style="color:#000088">if</span>((n = read(server_sock_fd, recv_msg, BUFFER_SIZE)) <<span style="color:#006666">0</span> )
{
<span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"read error!"</span>);
}
ev.data.fd=server_sock_fd;
ev.events=EPOLLOUT|EPOLLET;
<span style="color:#4f4f4f">printf</span>(<span style="color:#009900">"%s\n"</span>,recv_msg);
}
}
}
}
<span style="color:#000088">return</span> <span style="color:#006666">0</span>;
} </code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
2、關於epoll函式:
相比於select,epoll最大的好處在於它不會隨著監聽fd數目的增長而降低效率。因為在核心中的select實現中,它是採用輪詢來處理的,輪詢的fd數目越多,自然耗時越多。並且,在linux/posix_types.h標頭檔案有這樣的宣告:
#define __FD_SETSIZE 1024
表示select最多同時監聽1024個fd
一共三個函式:
1、 int epoll_create (int size);
建立一個epoll的控制代碼
*size用來告訴核心這個監聽的數目一共有多大。這個引數不同於select()中的第一個引數,給出最大監聽的fd+1的值。需要注意的是,當建立好epoll控制代碼後,它就是會佔用一個fd值,在linux下如果檢視/proc/程序id/fd/,是能夠看到這個fd的,所以在使用完epoll後,必須呼叫close()關閉,否則可能導致fd被耗盡。
2、 int epoll_ctl (int epfd , int op, int fd, struct epoll_event *event);
<span style="color:#000000"><code> epoll的事件註冊函式,它不同與select()是在監聽事件時告訴核心要監聽什麼型別的事件,而是在這裡先註冊要監聽的事件型別。第一個引數是epoll_create()的返回值,第二個引數表示動作,用三個巨集來表示:
</code></span>
- 1
- 2
- EPOLL_CTL_ADD:註冊新的fd到epfd中;
- EPOLL_CTL_MOD:修改已經註冊的fd的監聽事件;
- EPOLL_CTL_DEL:從epfd中刪除一個fd;
第三個引數是需要監聽的fd
第四個引數是告訴核心需要監聽什麼事,struct epoll_event結構如下:
<span style="color:#000000"><code><span style="color:#000088">struct</span> epoll_event {
__uint32_t events; <span style="color:#880000">/* Epoll events */</span>
epoll_data_t data; <span style="color:#880000">/* User data variable */</span>
};</code></span>
- 1
- 2
- 3
- 4
<span style="color:#000000"><code><span style="color:#000088">typedef</span> <span style="color:#000088">union</span> epoll_data {
<span style="color:#000088">void</span> *ptr;
<span style="color:#000088">int</span> fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
events可以是以下幾個巨集的集合:
- EPOLLIN :表示對應的檔案描述符可以讀(包括對端SOCKET正常關閉);
- EPOLLOUT:表示對應的檔案描述符可以寫;
- EPOLLPRI:表示對應的檔案描述符有緊急的資料可讀(這裡應該表示有帶外資料到來);
- EPOLLERR:表示對應的檔案描述符發生錯誤;
- EPOLLHUP:表示對應的檔案描述符被結束通話;
- EPOLLET: 將EPOLL設為邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來說的。
- EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL佇列裡
3、 int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
- 等待事件的產生,類似於select()呼叫。
- 引數events用來從核心得到事件的集合,
- maxevents告之核心這個events有多大,這個 maxevents的值不能大於建立epoll_create()時的size,
- 引數timeout是超時時間(毫秒,0會立即返回,-1將不確定,也有說法說是永久阻塞)。該函式返回需要處理的事件數目,如返回0表示已超時。
使用步驟:
<span style="color:#000000"><code> <1>首先通過create_epoll(int maxfds)來建立一個epoll的控制代碼,其中maxfds為你epoll所支援的最大控制代碼數。這個函式會返回一個新的epoll控制代碼,之後的所有操作將通過這個控制代碼來進行操作。在用完之後,記得用close()來關閉這個創建出來的epoll控制代碼。
<2>然後每一幀的呼叫epoll_wait (int epfd, epoll_event events, int max events, int timeout) 來查詢所有的網路介面。
<3>kdpfd為用epoll_create建立之後的控制代碼,events是一個epoll_event*的指標,當epoll_wait這個函式操作成功之後,epoll_events裡面將儲存所有的讀寫事件。max_events是當前需要監聽的所有socket控制代碼數。最後一個timeout是 epoll_wait的超時,為0的時候表示馬上返回,為-1的時候表示一直等下去,直到有事件範圍,為任意正整數的時候表示等這麼長的時間,如果一直沒有事件,則返回。一般如果網路主迴圈是單獨的執行緒的話,可以用-1來等,這樣可以保證一些效率,如果是和主邏輯在同一個執行緒的話,則可以用0來保證主迴圈的效率。
epoll_wait返回之後應該是一個迴圈,遍歷所有的事件。
</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
基本上都是如下的框架:
<span style="color:#000000"><code><span style="color:#000088">for</span>( ; ; )
{
nfds = epoll_wait(epfd,events,<span style="color:#006666">20</span>,<span style="color:#006666">500</span>);
<span style="color:#000088">for</span>(i=<span style="color:#006666">0</span>;i<nfds;++i)
{
<span style="color:#000088">if</span>(events[i].data.fd==listenfd) <span style="color:#880000">//有新的連線</span>
{
connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen); <span style="color:#880000">//accept這個連線</span>
ev.data.fd=connfd;
ev.events=EPOLLIN|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev); <span style="color:#880000">//將新的fd新增到epoll的監聽佇列中</span>
}
<span style="color:#000088">else</span> <span style="color:#000088">if</span>( events[i].events&EPOLLIN ) <span style="color:#880000">//接收到資料,讀socket</span>
{
n = read(sockfd, line, MAXLINE)) < <span style="color:#006666">0</span> <span style="color:#880000">//讀</span>
ev.data.ptr = md; <span style="color:#880000">//md為自定義型別,新增資料</span>
ev.events=EPOLLOUT|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);<span style="color:#880000">//修改識別符號,等待下一個迴圈時傳送資料,非同步處理的精髓</span>
}
<span style="color:#000088">else</span> <span style="color:#000088">if</span>(events[i].events&EPOLLOUT) <span style="color:#880000">//有資料待發送,寫socket</span>
{
<span style="color:#000088">struct</span> myepoll_data* md = (myepoll_data*)events[i].data.ptr; <span style="color:#880000">//取資料</span>
sockfd = md->fd;
send( sockfd, md->ptr, <span style="color:#4f4f4f">strlen</span>((<span style="color:#000088">char</span>*)md->ptr), <span style="color:#006666">0</span> ); <span style="color:#880000">//傳送資料</span>
ev.data.fd=sockfd;
ev.events=EPOLLIN|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); <span style="color:#880000">//修改識別符號,等待下一個迴圈時接收資料</span>
}
<span style="color:#000088">else</span>
{
<span style="color:#880000">//其他的處理</span>
}
}
}</code></span>