1.服务器端:
1.创建socket: 通过函数socket
2.绑定ip及端口:通过函数bind
1.需要构建一个sockaddt_in 结构体,并通过menset或bzore重置,传入bind为参数时显示转类型为sockaddr.
2.ip由字符串转为in_addr 结构体,可以通过inet_pton() 或其他函数,inet_pton函数会处理大小端问题;
3.端口,需要转大小端.ntohs 函数处理
3.监听端口:通过函数listen
//开始循环
//此时等待客户端连接
//会出现的问题:客户端完成3次握手后,发送了一个重置信号,此时,该客户端的连接通常有内核处理,而不到accept
4.阻塞获取数据:accept
1.该函数返回一个新的socket,参数为值-返回参数,需要一个空的sockaddr结构体,及该结构长度的指针
2.sockaddr结构体 可以声明sockaddr_in 代替,该结构体存储的信息为客户端的IP信息等
5.处理连接:
1.fock一个进程进行处理(开销大),连接等信息会拷贝一套由内核管理指针,当所指向的引用为0时关闭连接.
1.父进程不处理连接的情况下关闭父进程中的链接
2.子进程处理连接,之后关闭
//会出现的问题:子进程处理完后,调用exit,此时内核会发SIGCHLD信号到父进程,
//父进程必须处理该信号,否则子进程僵死,用此方法需要注册signal
2.使用IO复用
1.把socket注册到select或poll中,有连接的时候会触发调用,(注意设置超时)
3.使用线程处理
1.***
2.客户端:
1.创建socket: 通过函数socket
2.绑定ip及端口:通过函数bind
1.需要构建一个sockaddt_in 结构体,并通过menset或bzore重置,传入bind为参数时显示转类型为sockaddr.
2.ip由字符串转为in_addr 结构体,可以通过inet_pton() 或其他函数,inet_pton函数会处理大小端问题;
3.端口,需要转大小端.ntohs 函数处理
3.连接服务器:通过函数connect
1.返回连接的状态
2.该函数返回一个新的socket,参数为值-返回参数,需要一个空的sockaddr结构体,及该结构长度的指针
关于sockaddr结构体
sockaddr 跟sockaddr_in sockaddr_in6 sockaddr_storage 是可相互转换的
sockaddr_storage 结构体兼容IPV4 IPV6,所以取值时可以用该结构体进行接值:accept connect
sockaddr_in 用于IPV4的结构体,该结构体里成员分别为 sin_family(协议族) sin_port(端口) sin_addr (in_addr 结构体)
sockaddr_in6 跟sockaddr_in类似,但用于IPV6
当从函数accept或connect等函数得到的sockaddr 结构体时,需要转换为 sockaddr_in 或sockaddr_in6,
之后在通过inet_ntop可得到可读的IP等信息
sockaddr_storage 结构体通常用于sockaddr 结构体的传递,因为兼容IPV4跟IPV6
IO复用
select 函数
结构体:fd_set 一般是一个位数组
参数:最大的IO ID,可读时候的fd_set,可写时候的fd_set,异常时候的fd_set,超时
返回:-1 错误,0 超时返回,大于0 有可用IO
配套的宏:
FD_ZERO(&set); //将fd_set的结构体重置为0
FD_SET(in,&set);//增加要监听的IO进fd_set,所有用于select的fd_set都需要增加监听
FD_ISSET(in,&set);//判断指定IO是否可读,写,异常
FD_CLR(&set);//清理已监听入fd_set的IO
struct timeval t;//时间结构体
实例:
int in= fileno(stdin); char x1[100]; fd_set set; while(1){ FD_ZERO(&set);//重置 FD_SET(in,&set);//增加 int r=select(in+1,&set,NULL,NULL,NULL);//监听,当有IO可操作的时候,改函数修改可操作IO的那个位 if(r>0){ if(FD_ISSET(in,&set)){//判断到可操作的那个IO位与指定的IO相同,返回真 fgets(x1,100,stdin);//如果不读出数据,IO将永远处于可用状态 printf("stdin",x1); } }else{ printf("bad"); } }
poll 函数:
http://bbs.chinaunix.net/thread-1740200-1-1.html
实现上述类似功能:
struct pollfd fds[CMAX]; int in= fileno(stdin); int out= fileno(stdout); fds[0].fd=in; fds[0].events=POLLIN;// 可以多个事件 POLLIN|POLLOUT char a[100]; memset(a,0,100); fds[1].fd=out; fds[1].events=POLLOUT; FILE *f; f=fopen("./txt","a"); enum {
SN,
SB
} S; S=SN; while(1){
if(S==SB)
break; if( poll(fds,CMAX,0)>0){ int i=0; for(;i<CMAX;i++){ if(fds[i].revents==POLLIN){//判断返回事件 read(in,a,100); if(a[0]=='q'){ printf("%s","fasdfas");
S=SB;
} printf("in:%s",a); fwrite(a, strlen(a), 1, f); } } } } fclose(f); return EXIT_SUCCESS;
linux 支持的事件列表:(来自man)
POLLIN There is data to read. POLLPRI There is urgent data to read (e.g., out-of-band data on TCP socket; pseudo-terminal master in packet mode has seen state change in slave). POLLOUT Writing now will not block. POLLRDHUP (since Linux 2.6.17) Stream socket peer closed connection, or shut down writing half of connection. The _GNU_SOURCE feature test macro must be defined in order to obtain this definition. POLLERR Error condition (output only). POLLHUP Hang up (output only). POLLNVAL Invalid request: fd not open (output only). When compiling with _XOPEN_SOURCE defined, one also has the following, which convey no further information beyond the bits listed above: POLLRDNORM Equivalent to POLLIN. POLLRDBAND Priority band data can be read (generally unused on Linux). POLLWRNORM Equivalent to POLLOUT. POLLWRBAND Priority data may be written.
以上两种均属于:Edge Triggered 只要缓存区中有未处理的数据,将触发系统调用
epoll 系列函数
支持 Level Triggered 跟 Edge Triggered 模式
实例:http://www.cppblog.com/converse/archive/2008/04/29/48482.html