1、关于字节排序 网际协议采用大端字节序,来传输多字节整数。 系统提供了转换的宏定义,如果主机与网际协议相同,则宏定义为空。
2、客户端 socket -> connect(阻塞,三次握手)-> rcv
3、服务器端 socket -> bind -> listen -> accept(阻塞,三次握手)-> send4、函数介绍
a..socket
1)函数原型 int socket(int family, int type, int protocol)
2)参数: family: 协议族AF_INET,IPv4协议 ... type : type 套接字类型SOCK_STREAM 字节流套接字 protocol: IPPROCO_TCP IPPROCO_UDP IPPROCO_SCTP
3)返回值 成功:返回套接字符 错误:返回INVALID_SOCKET(-1)
4)示例
#include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> int main() { int socketfd; struct sockaddr_in servaddr; if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { return -1; } }
#include <stdio.h> #include <string.h> #include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> int main() { int socketfd; struct sockaddr_in servaddr; if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("socket error\n"); return -1; } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_addr.s_addr = inet_addr("192.168.0.218"); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(55000); if(connect(socketfd, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0) { printf("connect error\n"); } return 0; }
4)示例
#include <stdio.h> #include <string.h> #include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> int main() { int count = 0; int listenfd, socketfd; int nread; struct sockaddr_in servaddr; struct timeval timeoutval; char readbuf[256]; printf("accept started\n"); //socket if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("socket error\n"); return -1; } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(59000); //bind if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { printf("bind error\n"); //return -1; } //listen listen(listenfd, 5); //accept socketfd = accept(listenfd, NULL, NULL); while(1) { printf("start receive %d...\n", count++); memset(readbuf, sizeof(readbuf), 0); nread = recv(socketfd, readbuf, 10, 0); if(nread>0) { readbuf[10] = '\0'; printf("receiveed %s, nread = %d\n\n", readbuf, nread); } } return 0; }
/* 实现功能:通过select处理多个socket * 监听一个端口,监听到有链接时,添加到select的w. */ #include "select.h" #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <sys/select.h> #include <sys/time.h> #include <netinet/in.h> typedef struct _CLIENT{ int fd; struct sockaddr_in addr; /* client's address information */ } CLIENT; #define MYPORT 59000 //最多处理的connect #define BACKLOG 5 //最多处理的connect CLIENT client[BACKLOG]; //当前的连接数 int currentClient = 0; //数据接受 buf #define REVLEN 10 char recvBuf[REVLEN]; //显示当前的connection void showClient(); int main() { int i, ret, sinSize; int recvLen = 0; fd_set readfds, writefds; int sockListen, sockSvr, sockMax; struct timeval timeout; struct sockaddr_in server_addr; struct sockaddr_in client_addr; for(i=0; i<BACKLOG; i++) { client[i].fd = -1; } //socket if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("socket error\n"); return -1; } bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(MYPORT); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //bind if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { printf("bind error\n"); return -1; } //listen if(listen(sockListen, 5) < 0) { printf("listen error\n"); return -1; } for(i=0; i<BACKLOG; i++) { client[i].fd = -1; } //select while(1) { FD_ZERO(&readfds); FD_SET(sockListen, &readfds); sockMax = sockListen; //加入client for(i=0; i<BACKLOG; i++) { if(client[i].fd >0) { FD_SET(client[i].fd, &readfds); if(sockMax<client[i].fd) sockMax = client[i].fd; } } timeout.tv_sec=3; timeout.tv_usec=0; //select ret = select((int)sockMax+1, &readfds, NULL, NULL, &timeout); if(ret < 0) { printf("select error\n"); break; } else if(ret == 0) { printf("timeout ...\n"); continue; } printf("test111\n"); //读取数据 for(i=0; i<BACKLOG; i++) { if(client[i].fd>0 && FD_ISSET(client[i].fd, &readfds)) { if(recvLen != REVLEN) { while(1) { //recv数据 ret = recv(client[i].fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0); if(ret == 0) { client[i].fd = -1; recvLen = 0; break; } else if(ret < 0) { client[i].fd = -1; recvLen = 0; break; } //数据接受正常 recvLen = recvLen+ret; if(recvLen<REVLEN) { continue; } else { //数据接受完毕 printf("%s, buf = %s\n", inet_ntoa(client[i].addr.sin_addr) , recvBuf); //close(client[i].fd); //client[i].fd = -1; recvLen = 0; break; } } } } } //如果可读 if(FD_ISSET(sockListen, &readfds)) { printf("isset\n"); sockSvr = accept(sockListen, NULL, NULL);//(struct sockaddr*)&client_addr if(sockSvr == -1) { printf("accpet error\n"); } else { currentClient++; } for(i=0; i<BACKLOG; i++) { if(client[i].fd < 0) { client[i].fd = sockSvr; client[i].addr = client_addr; printf("You got a connection from %s \n",inet_ntoa(client[i].addr.sin_addr) ); break; } } //close(sockListen); } } printf("test\n"); return 0; } //显示当前的connection void showClient() { int i; printf("client count = %d\n", currentClient); for(i=0; i<BACKLOG; i++) { printf("[%d] = %d", i, client[i].fd); } printf("\n"); }
5) 示例
/* 实现功能:通过poll, 处理多个socket * 监听一个端口,监听到有链接时,添加到poll. */ #include "select.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <poll.h> #include <sys/time.h> #include <netinet/in.h> typedef struct _CLIENT{ int fd; struct sockaddr_in addr; /* client's address information */ } CLIENT; #define MYPORT 59000 //最多处理的connect #define BACKLOG 5 //当前的连接数 int currentClient = 0; //数据接受 buf #define REVLEN 10 char recvBuf[REVLEN]; #define OPEN_MAX 1024 int main() { int i, ret, sinSize; int recvLen = 0; fd_set readfds, writefds; int sockListen, sockSvr, sockMax; int timeout; struct sockaddr_in server_addr; struct sockaddr_in client_addr; struct pollfd clientfd[OPEN_MAX]; //socket if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("socket error\n"); return -1; } bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(MYPORT); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //bind if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { printf("bind error\n"); return -1; } //listen if(listen(sockListen, 5) < 0) { printf("listen error\n"); return -1; } //clientfd 初始化 clientfd[0].fd = sockListen; clientfd[0].events = POLLIN; //POLLRDNORM; sockMax = 0; for(i=1; i<OPEN_MAX; i++) { clientfd[i].fd = -1; } //select while(1) { timeout=3000; //select ret = poll(clientfd, sockMax+1, timeout); if(ret < 0) { printf("select error\n"); break; } else if(ret == 0) { printf("timeout ...\n"); continue; } if (clientfd[0].revents & POLLIN)//POLLRDNORM { sockSvr = accept(sockListen, NULL, NULL);//(struct sockaddr*)&client_addr if(sockSvr == -1) { printf("accpet error\n"); } else { currentClient++; } for(i=0; i<OPEN_MAX; i++) { if(clientfd[i].fd<0) { clientfd[i].fd = sockSvr; break; } } if(i==OPEN_MAX) { printf("too many connects\n"); return -1; } clientfd[i].events = POLLIN;//POLLRDNORM; if(i>sockMax) sockMax = i; } //读取数据 for(i=1; i<=sockMax; i++) { if(clientfd[i].fd < 0) continue; if (clientfd[i].revents & (POLLIN | POLLERR))//POLLRDNORM { if(recvLen != REVLEN) { while(1) { //recv数据 ret = recv(clientfd[i].fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0); if(ret == 0) { clientfd[i].fd = -1; recvLen = 0; break; } else if(ret < 0) { clientfd[i].fd = -1; recvLen = 0; break; } //数据接受正常 recvLen = recvLen+ret; if(recvLen<REVLEN) { continue; } else { //数据接受完毕 printf("buf = %s\n", recvBuf); //close(client[i].fd); //client[i].fd = -1; recvLen = 0; break; } } } } } } return 0; }
/* 实现功能:通过epoll, 处理多个socket * 监听一个端口,监听到有链接时,添加到epoll_event */ #include "select.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <poll.h> #include <sys/epoll.h> #include <sys/time.h> #include <netinet/in.h> typedef struct _CLIENT{ int fd; struct sockaddr_in addr; /* client's address information */ } CLIENT; #define MYPORT 59000 //最多处理的connect #define MAX_EVENTS 500 //当前的连接数 int currentClient = 0; //数据接受 buf #define REVLEN 10 char recvBuf[REVLEN]; //EPOLL相关 //epoll描述符 int epollfd; //事件数组 struct epoll_event eventList[MAX_EVENTS]; void AcceptConn(int srvfd); void RecvData(int fd); int main() { int i, ret, sinSize; int recvLen = 0; fd_set readfds, writefds; int sockListen, sockSvr, sockMax; int timeout; struct sockaddr_in server_addr; struct sockaddr_in client_addr; //socket if((sockListen=socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("socket error\n"); return -1; } bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(MYPORT); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //bind if(bind(sockListen, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { printf("bind error\n"); return -1; } //listen if(listen(sockListen, 5) < 0) { printf("listen error\n"); return -1; } //1. epoll 初始化 epollfd = epoll_create(MAX_EVENTS); struct epoll_event event; event.events = EPOLLIN|EPOLLET; event.data.fd = sockListen; //2. epoll_ctrl if(epoll_ctl(epollfd, EPOLL_CTL_ADD, sockListen, &event) < 0) { printf("epoll add fail : fd = %d\n", sockListen); return -1; } //epoll while(1) { timeout=3000; //3. epoll_wait int ret = epoll_wait(epollfd, eventList, MAX_EVENTS, timeout); if(ret < 0) { printf("epoll error\n"); break; } else if(ret == 0) { printf("timeout ...\n"); continue; } //直接获取了事件数量,给出了活动的流,这里是和poll区别的关键 int n = 0; for(n=0; n<ret; n++) { //错误退出 if ((eventList[n].events & EPOLLERR) || (eventList[n].events & EPOLLHUP) || !(eventList[n].events & EPOLLIN)) { printf ( "epoll error\n"); close (eventList[n].data.fd); return -1; } if (eventList[n].data.fd == sockListen) { AcceptConn(sockListen); }else{ RecvData(eventList[n].data.fd); //不删除 // epoll_ctl(epollfd, EPOLL_CTL_DEL, pEvent->data.fd, pEvent); } } } close(epollfd); close(sockListen); printf("test\n"); return 0; } /************************************************** 函数名:AcceptConn 功能:接受客户端的链接 参数:srvfd:监听SOCKET ***************************************************/ void AcceptConn(int srvfd) { struct sockaddr_in sin; socklen_t len = sizeof(struct sockaddr_in); bzero(&sin, len); int confd = accept(srvfd, (struct sockaddr*)&sin, &len); if (confd < 0) { printf("bad accept\n"); return; }else { printf("Accept Connection: %d", confd); } //setnonblocking(confd); //4. epoll_wait //将新建立的连接添加到EPOLL的监听中 struct epoll_event event; event.data.fd = confd; event.events = EPOLLIN|EPOLLET; epoll_ctl(epollfd, EPOLL_CTL_ADD, confd, &event); } //读取数据 void RecvData(int fd) { int ret; int recvLen = 0; memset(recvBuf, 0, REVLEN); printf("RecvData function\n"); if(recvLen != REVLEN) { while(1) { //recv数据 ret = recv(fd, (char *)recvBuf+recvLen, REVLEN-recvLen, 0); if(ret == 0) { recvLen = 0; break; } else if(ret < 0) { recvLen = 0; break; } //数据接受正常 recvLen = recvLen+ret; if(recvLen<REVLEN) { continue; } else { //数据接受完毕 printf("buf = %s\n", recvBuf); recvLen = 0; break; } } } printf("content is %s", recvBuf); }