注:實驗代碼來自於網絡,在原代碼中只增加了一些打印代碼。
本文僅作複習筆記之用,以備日後查閱。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
//#include <openssl/ssl.h>
//#include <openssl/err.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <pthread.h>
#include <assert.h>
//#include "oci_api.h"
#define MAXBUF 1024
#define MAXEPOLLSIZE 100
/*
setnonblocking ?C ???þ???Ϊ????????ʽ
*/
int setnonblocking(int sockfd)
{
if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1)
{
return -1;
}
return 0;
}
/*
pthread_handle_message ?C ?̴߳??? socket ?ϵ???Ϣ?շ?
*/
void* pthread_handle_message(int* sock_fd)
{
char recvbuf[MAXBUF + 1];
char sendbuf[MAXBUF+1];
int ret;
int new_fd;
struct sockaddr_in client_addr;
socklen_t cli_len=sizeof(client_addr);
new_fd=*sock_fd;
/* ??ʼ????ÿ????l???ϵ??????շ? */
bzero(recvbuf, MAXBUF + 1);
bzero(sendbuf, MAXBUF + 1);
/* ???տͻ??˵???Ϣ */
ret = recvfrom(new_fd, recvbuf, MAXBUF, 0, (struct sockaddr *)&client_addr, &cli_len);
if (ret > 0){
printf("socket: %d \n recv from : %s : %d \n message: %s \n ??%d bytes \n",
new_fd, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), recvbuf, ret);
/*
char *s1="insert";
char *s2="select";
char *s3="delete";
if(!strncmp(s1,recvbuf,6))
oci_insert(recvbuf,sendbuf);
else if(!strncmp(s2,recvbuf,6))
oci_select(recvbuf,sendbuf);
else if(!strncmp(s3,recvbuf,6))
oci_delete(recvbuf,sendbuf);
else
sprintf(sendbuf,"input sql is error!/n");
ret = sendto(new_fd, sendbuf, strlen(sendbuf), 0, (struct sockaddr *)&client_addr, cli_len);
if(ret<0)
printf("??Ϣ????ʧ?ܣ???????????%d????????Ϣ??'%s'/n", errno, strerror(errno));
*/
}
else
{
printf("received failed! error code %d ??message : %s \n",
errno, strerror(errno));
}
/* ????ÿ????l???ϵ??????շ????? */
//printf("pthread exit!");
fflush(stdout);
pthread_exit(NULL);
}
int main(int argc, char **argv)
{
int listener, kdpfd, nfds, n, curfds;
socklen_t len;
struct sockaddr_in my_addr, their_addr;
unsigned int myport;
struct epoll_event ev;
struct epoll_event events[MAXEPOLLSIZE];
struct rlimit rt;
myport = 1234;
printf("port setting 1234 success \n");
pthread_t thread;
pthread_attr_t attr;
/* ????ÿ???????????�??????ļ??? */
rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
if (setrlimit(RLIMIT_NOFILE, &rt) == -1)
{
perror("setrlimit");
exit(1);
}
else
{
printf("setting success \n");
}
printf("setting success \n");
/* ???? socket ???? */
if ((listener = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("socket create failed ??");
exit(1);
}
else
{
printf("socket create success /n");
}
printf("3 setting success \n");
/*????socket???ԣ??˿ڿ???????*/
int opt=SO_REUSEADDR;
setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
setnonblocking(listener);
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = PF_INET;
my_addr.sin_port = htons(myport);
/*
my_addr.sin_addr.s_addr = INADDR_ANY;
*/
my_addr.sin_addr.s_addr = inet_addr("192.168.34.52");
printf("4 setting success \n");
/*
printf("socket : %s \n", inet_ntoa((my_addr.sin_addr));
*/
printf("socket : %s \n", inet_ntoa(my_addr.sin_addr));
if (bind(listener, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1)
{
printf("socket : %s \n", inet_ntoa(my_addr.sin_addr));
perror("bind error! \n");
exit(1);
}
else
{
printf("IP and port bind success \n");
printf("port: %d \n",ntohs(my_addr.sin_port));
}
/* ???? epoll ???????Ѽ??? socket ???뵽 epoll ?????? */
kdpfd = epoll_create(MAXEPOLLSIZE);
len = sizeof(struct sockaddr_in);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = listener;
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev) < 0)
{
fprintf(stderr, "epoll set insertion error: fd=%d \n", listener);
return -1;
}
else
{
printf("111112223333listen socket added in epoll success \n");
}
while (1)
{
/* ?ȴ????¼????? */
printf("6666666listen socket added in epoll success \n");
printf("7777777 kdpfd values: %d \n",kdpfd);
nfds = epoll_wait(kdpfd, events, 10,-1 );
printf("nfds values: %d ",nfds);
if (nfds == -1)
{
perror("epoll_wait \n");
break;
}
printf(" epoll wait ok \n");
/* ?????????¼? */
for (n = 0; n < nfds; ++n)
{
if (events[n].data.fd == listener)
{
/*??ʼ??????ֵ??????ΪĬ??ֵ*/
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
/* ?????߳?Ϊ????????*/
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if(pthread_create(&thread,&attr,(void*)pthread_handle_message,(void*)&(events[n].data.fd)))
{
perror("pthread_creat error!");
exit(-1);
}
}
}
}
close(listener);
return 0;
}
查看目錄裏的內容:
說明:編譯udpepoll.c文件時,必須要加”-g“ 選項,要不後面無法用gdb調試。
root@ubuntu:/home/lin/epoll/udp# ls
udpepoll.c up
”up“爲編譯後的文件,通過gdb加載調試:
root@ubuntu:/home/lin/epoll/udp# gdb up
GNU gdb (Ubuntu/Linaro 7.4-2012.02-0ubuntu2) 7.4-2012.02
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/lin/epoll/udp/up...done.
(gdb) l 214
209 printf("6666666listen socket added in epoll success \n");
210
211 printf("7777777 kdpfd values: %d \n",kdpfd);
212 nfds = epoll_wait(kdpfd, events, 10,-1 );
213 printf("nfds values: %d ",nfds);
214 if (nfds == -1)
215 {
216 perror("epoll_wait \n");
217 break;
218 }
查看斷點信息:
(gdb) info b
No breakpoints or watchpoints.
上面顯示無斷點,所以在代碼”udpepoll.c“文件中的 214行設置斷點:
(gdb) b 214
Breakpoint 1 at 0x8048fea: file udpepoll.c, line 214.
(gdb) c
The program is not being run.
執行程序:
(gdb) r
Starting program: /home/lin/epoll/udp/up
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
port setting 1234 success
setting success
setting success
socket create success /n3 setting success
4 setting success
socket : 192.168.34.52
IP and port bind success
port: 1234
111112223333listen socket added in epoll success
6666666listen socket added in epoll success
7777777 kdpfd values: 8
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/lin/epoll/udp/up
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
port setting 1234 success
setting success
setting success
socket create success /n3 setting success
4 setting success
socket : 192.168.34.52
IP and port bind success
port: 1234
111112223333listen socket added in epoll success
6666666listen socket added in epoll success
Breakpoint 1, main (argc=1, argv=0xbffff264) at udpepoll.c:211
211 printf("7777777 kdpfd values: %d \n",kdpfd);
(gdb) n
7777777 kdpfd values: 8
212 nfds = epoll_wait(kdpfd, events, 10,-1 );
(gdb)
213 printf("nfds values: %d ",nfds);
(gdb)
214 if (nfds == -1)
(gdb)
221 printf(" epoll wait ok \n");
(gdb)
nfds values: 1 epoll wait ok
223 for (n = 0; n < nfds; ++n)
(gdb)
225 if (events[n].data.fd == listener)
(gdb)
228 pthread_attr_init(&attr);
(gdb)
229 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
(gdb)
233 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
(gdb)
236 if(pthread_create(&thread,&attr,(void*)pthread_handle_message,(void*)&(events[n].data.fd)))
查看線程信息:
(gdb) info threads
Id Target Id Frame
* 1 Thread 0xb7e076c0 (LWP 23445) "up" main (argc=1, argv=0xbffff264) at udpepoll.c:236
(gdb) n
[New Thread 0xb7e06b40 (LWP 23450)]
223 for (n = 0; n < nfds; ++n)
(gdb)
244 }
還是查看線程信息:
(gdb) info threads
Id Target Id Frame
2 Thread 0xb7e06b40 (LWP 23450) "up" 0xb7ef3ab8 in clone () from /lib/i386-linux-gnu/libc.so.6
* 1 Thread 0xb7e076c0 (LWP 23445) "up" main (argc=1, argv=0xbffff264) at udpepoll.c:244
上面查到當前有兩個線程,看最前面的序號,”*1“ 是代表當前線程,而我們要進入線程2 裏進行調試,因此需要切換線程。
如下:
(gdb) thread 2
[Switching to thread 2 (Thread 0xb7e06b40 (LWP 23450))]
#0 0xb7ef3ab8 in clone () from /lib/i386-linux-gnu/libc.so.6
再查看線程信息:
(gdb) info threads
Id Target Id Frame
* 2 Thread 0xb7e06b40 (LWP 23450) "up" 0xb7ef3ab8 in clone () from /lib/i386-linux-gnu/libc.so.6
1 Thread 0xb7e076c0 (LWP 23445) "up" main (argc=1, argv=0xbffff264) at udpepoll.c:244
單步執行:
(gdb) n
Single stepping until exit from function clone,
which has no line number information.
0xb7fb4c80 in start_thread () from /lib/i386-linux-gnu/libpthread.so.0
(gdb)
Single stepping until exit from function start_thread,
which has no line number information.
Breakpoint 2, pthread_handle_message (sock_fd=0xbfffec98) at udpepoll.c:51
51 socklen_t cli_len=sizeof(client_addr);
(gdb)
54 new_fd=*sock_fd;
注意:如下設置
(gdb) set scheduler-locking on
說明,多線程時,線程是同時運行的,要保證始終在本線程內調試,需做上述的操作。
(gdb) n
58 bzero(recvbuf, MAXBUF + 1);
(gdb)
59 bzero(sendbuf, MAXBUF + 1);
(gdb)
63 ret = recvfrom(new_fd, recvbuf, MAXBUF, 0, (struct sockaddr *)&client_addr, &cli_len);
查看變量值:
(gdb) p ret
$4 = 0
(gdb) n
64 if (ret > 0){
查看變量值:
(gdb) p ret
$5 = 10
查看從客戶端接收到是內容:
保存在recvbuf變量內。
(gdb) p recvbuf
$6 = "1122334488", '\000' <repeats 1014 times>
(gdb)
說明:
上面的操作過程,有些步驟重複,主要該程序是服務器端程序,需要客戶端連接後,併發送數據。而實驗過程中忘記了從客戶端向服務器端發送數據包,當完成客戶端操作後,服務器調試時未從新操作,因此有了重複步驟。
客戶端使用網絡上的調試工具: