注:实验代码来自于网络,在原代码中只增加了一些打印代码。
本文仅作复习笔记之用,以备日后查阅。
#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)
说明:
上面的操作过程,有些步骤重复,主要该程序是服务器端程序,需要客户端连接后,并发送数据。而实验过程中忘记了从客户端向服务器端发送数据包,当完成客户端操作后,服务器调试时未从新操作,因此有了重复步骤。
客户端使用网络上的调试工具: