socket编程(六)
来源:互联网 发布:被淘宝内部优惠券骗了 编辑:程序博客网 时间:2024/06/06 19:01
1.TCP/IP回射客户/服务器
2.TCP是个流协议
(1)TCP是个基于字节流传输的,只维护发送出去多少,确认了多少,没有维护消息与消息之间的边界,因而可能导致粘包问题。
(2)粘包问题解决方法是在应用层维护消息边界。
3.僵进程与SIGCHLD信号
(1)signal(SIGCHLD, SIG_IGN);
(2)signal(SIGCHLD, handle_sigchld);
echoserver.cpp
#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#include <sys/wait.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ }while(0) /* param1:fd, param2:buf, param3:countreturn:读取成功字节数ssize_t:有符号size_t:无符号 */ssize_t readn(int fd, void* buf, size_t count) {size_t nleft = count;ssize_t nread; //已经读了char* bufp = (char*)buf;while(nleft > 0) {if((nread = read(fd, bufp, nleft)) < 0) {if(errno == EINTR) continue;return -1;} else if (0 == nread) {return count - nleft;}bufp += nread;nleft -= nread;}return count;}/*param1:fd, param2:buf, param3:countreturn:已经发送了多少*/ssize_t writen(int fd, void* buf, size_t count) {size_t nleft = count;ssize_t nwrite;char* bufp = (char*)buf;while(nleft > 0) {if((nwrite = write(fd, bufp, nleft)) < 0) {if(errno == EINTR)continue;return -1;} else if(0 == nwrite) {continue;}bufp += nwrite;nleft -= nwrite;}return count;}//从套接口接收数据,但是不从缓冲区中移除MSG_PEEK//只要有偷看到数据就接收,没有头看到就是阻塞//对方套接口关闭,返回0ssize_t recv_peek(int sockfd, void* buf, size_t len) {while(1) {int ret = recv(sockfd, buf, len, MSG_PEEK);if(-1 == ret && errno == EINTR) continue;return ret;}}//读取遇到\r\n截止,最大不能超过maxlinessize_t readline(int sockfd, void* buf, size_t maxline) {int ret;int nread;int nleft = maxline;char* bufp = (char*)buf;while(1) {//信号中断已在recv_peek中处理ret = recv_peek(sockfd, bufp, nleft);if(ret < 0) return ret;if(0 == ret) //表示对方关闭套接口 return ret;nread = ret; //实际偷看到的字节数int i;//该缓冲区中有\n,read读走for(i=0; i<nread; i++) {if(bufp[i] == '\n') {ret = readn(sockfd, bufp, i+1); //包括\n都读走if(ret != i+1) exit(EXIT_FAILURE);return ret;}}//没有\n,read先读走这部分,然后bufp偏移if(nread > nleft) exit(EXIT_FAILURE);nleft -= nread; //更新剩余量ret = readn(sockfd, bufp, nread); if(ret != nread) exit(EXIT_FAILURE);bufp += nread;}return -1;}void echo_srv(int conn) { char recvbuf[1024]; //struct packet recvbuf;int n; while(1) { memset(&recvbuf, 0, sizeof(recvbuf)); int ret = readline(conn, recvbuf, 1024);if(-1 == ret) {ERR_EXIT("readline");} else if(0 == ret) {printf("client close\n");break;} fputs(recvbuf, stdout); writen(conn, recvbuf, strlen(recvbuf)); }}void handle_sigchild(int sig) {//wait(NULL);//waitpid(-1, NULL, WNOHANG);while(waitpid(-1, NULL, WNOHANG) >0);}int main () {//1.避免僵尸进程//signal(SIGCHLD, SIG_IGN);signal(SIGCHLD, handle_sigchild); int listenfd;if(( listenfd= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) //if((listenfd= socket(PF_INET, SOCK_STREAM, 0)) <0) ERR_EXIT("socket"); struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); //servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //inet_aton("127.0.0.1", &servaddr.sin_addr); int on = 1;if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)ERR_EXIT("setsockopt"); if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr))<0) ERR_EXIT("bind"); if(listen(listenfd, SOMAXCONN) < 0) ERR_EXIT("listen"); struct sockaddr_in peeraddr; socklen_t peerlen = sizeof(peeraddr); int conn;pid_t pid;while(1) {//accept必须同时为NULL; 或者同时不为NULLif((conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0)ERR_EXIT("accept");//通过accept得到对端addr,portprintf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));struct sockaddr_in connaddr;socklen_t connlen = sizeof(connaddr);//通过getpeername得到对端addr,port[conn必须是已连接的套接字]//conn包含本段ip,port; 也包含对端ip,portgetpeername(conn, (struct sockaddr*)&connaddr, &connlen);printf("ip=%s port=%d\n", inet_ntoa(connaddr.sin_addr), ntohs(connaddr.sin_port));pid = fork();if(-1 == pid) {ERR_EXIT("fork");}if(pid == 0) { //child close(listenfd);echo_srv(conn);exit(EXIT_SUCCESS);} else {//parentclose(conn);} }close(listenfd);close(conn); return 0;}
echoclient.cpp
#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ }while(0) ssize_t readn(int fd, void* buf, size_t count) {size_t nleft = count;ssize_t nread; //已经读了char* bufp = (char*)buf;while(nleft > 0) {if((nread = read(fd, bufp, nleft)) < 0) {if(errno == EINTR) continue;return -1;} else if (0 == nread) {return count - nleft;}bufp += nread;nleft -= nread;}return count;}ssize_t writen(int fd, void* buf, size_t count) {size_t nleft = count;ssize_t nwrite;char* bufp = (char*)buf;while(nleft > 0) {if((nwrite = write(fd, bufp, nleft)) < 0) {if(errno == EINTR)continue;return -1;} else if(0 == nwrite) {continue;}bufp += nwrite;nleft -= nwrite;}return count;}ssize_t recv_peek(int sockfd, void* buf, size_t len) {while(1) {int ret = recv(sockfd, buf, len, MSG_PEEK);if(-1 == ret && errno == EINTR) continue;return ret;}}//读取遇到\r\n截止,最大不能超过maxlinessize_t readline(int sockfd, void* buf, size_t maxline) {int ret;int nread;char* bufp = (char*)buf;int nleft = maxline;while(1) {ret = recv_peek(sockfd, bufp, nleft);if(ret < 0) //信号中断 return ret;if(0 == ret) //表示对方关闭套接口 return ret;nread = ret;int i;//该缓冲区中有\n,read读走for(i=0; i<nread; i++) {if(bufp[i] == '\n') {ret = readn(sockfd, bufp, i+1); //包括\n都读走if(ret != i+1) exit(EXIT_FAILURE);return ret;}}//没有\n,read先读走这部分,然后bufp偏移if(nread > nleft) exit(EXIT_FAILURE);nleft -= nread;ret = readn(sockfd, bufp, nread); if(ret != nread) exit(EXIT_FAILURE);bufp += nread;}return -1;}void echo_cli(int sock) { char sendbuf[1024] = {0}; char recvbuf[1024] = {0}; int n; while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL) {//将带有\n的buf发送过去 writen(sock, sendbuf, strlen(sendbuf)); int ret = readline(sock, recvbuf, sizeof(recvbuf));if(-1 == ret) {ERR_EXIT("readline");} else if(0 == ret) {printf("client close\n");break;} fputs(recvbuf, stdout); memset(sendbuf, 0, sizeof(sendbuf)); memset(recvbuf, 0, sizeof(recvbuf)); }}int main () { int sock;if(( sock= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) ERR_EXIT("socket"); sock = socket(PF_INET, SOCK_STREAM, 0); struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); if(connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) ERR_EXIT("sockect"); //获得本端ip,portstruct sockaddr_in localaddr;socklen_t addrlen= sizeof(localaddr);if(getsockname(sock,(struct sockaddr*)&localaddr, &addrlen) < 0)ERR_EXIT("getsockname");printf("ip=%s port=%d\n", inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port));struct sockaddr_in connaddr;socklen_t connlen = sizeof(connaddr);//通过getpeername得到对端addr,port[conn必须是已连接的套接字]getpeername(sock, (struct sockaddr*)&connaddr, &connlen);printf("ip=%s port=%d\n", inet_ntoa(connaddr.sin_addr), ntohs(connaddr.sin_port)); echo_cli(sock); close(sock); return 0;}
fiveclient.cpp
#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ }while(0) ssize_t readn(int fd, void* buf, size_t count) {size_t nleft = count;ssize_t nread; //已经读了char* bufp = (char*)buf;while(nleft > 0) {if((nread = read(fd, bufp, nleft)) < 0) {if(errno == EINTR) continue;return -1;} else if (0 == nread) {return count - nleft;}bufp += nread;nleft -= nread;}return count;}ssize_t writen(int fd, void* buf, size_t count) {size_t nleft = count;ssize_t nwrite;char* bufp = (char*)buf;while(nleft > 0) {if((nwrite = write(fd, bufp, nleft)) < 0) {if(errno == EINTR)continue;return -1;} else if(0 == nwrite) {continue;}bufp += nwrite;nleft -= nwrite;}return count;}ssize_t recv_peek(int sockfd, void* buf, size_t len) {while(1) {int ret = recv(sockfd, buf, len, MSG_PEEK);if(-1 == ret && errno == EINTR) continue;return ret;}}//读取遇到\r\n截止,最大不能超过maxlinessize_t readline(int sockfd, void* buf, size_t maxline) {int ret;int nread;char* bufp = (char*)buf;int nleft = maxline;while(1) {ret = recv_peek(sockfd, bufp, nleft);if(ret < 0) //信号中断 return ret;if(0 == ret) //表示对方关闭套接口 return ret;nread = ret;int i;//该缓冲区中有\n,read读走for(i=0; i<nread; i++) {if(bufp[i] == '\n') {ret = readn(sockfd, bufp, i+1); //包括\n都读走if(ret != i+1) exit(EXIT_FAILURE);return ret;}}//没有\n,read先读走这部分,然后bufp偏移if(nread > nleft) exit(EXIT_FAILURE);nleft -= nread;ret = readn(sockfd, bufp, nread); if(ret != nread) exit(EXIT_FAILURE);bufp += nread;}return -1;}void echo_cli(int sock) { char sendbuf[1024] = {0}; char recvbuf[1024] = {0}; int n; while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL) {//将带有\n的buf发送过去 writen(sock, sendbuf, strlen(sendbuf)); int ret = readline(sock, recvbuf, sizeof(recvbuf));if(-1 == ret) {ERR_EXIT("readline");} else if(0 == ret) {printf("client close\n");break;} fputs(recvbuf, stdout); memset(sendbuf, 0, sizeof(sendbuf)); memset(recvbuf, 0, sizeof(recvbuf)); }}int main () { int sock[5];int i;for(i=0; i<5; i++) {if(( sock[i]= socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)ERR_EXIT("socket");//sock = socket(PF_INET, SOCK_STREAM, 0);struct sockaddr_in servaddr;memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(5188);servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");if(connect(sock[i], (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)ERR_EXIT("sockect");} echo_cli(sock[0]);for(i=0; i<5; i++) { close(sock[i]);} return 0;}
阅读全文
1 0
- socket编程(六)
- socket编程原理(六)
- MFC(六)——Socket编程
- SOCKET编程六种模型
- Java Socket网络编程六
- SOCKET编程六种模型
- Java网络编程学习笔记(六)服务器Socket
- C++ Socket(六)
- Socket编程(六)---TCP/NIO实例讲解
- Python自学笔记六、socket编程
- C#网络编程(六、Socket文件传输)
- Linux Socket学习(六)
- Linux Socket学习(六)
- socket的创建(六)
- socket的创建(六)
- socket的创建(六)
- linux网络编程之socket(六):利用recv和readn函数实现readline函数
- linux网络编程之socket(六):利用recv和readn函数实现readline函数
- Ruby语言入门之Hello world
- C判断字符输入是否为指定字符串
- 页 页表 页表项
- “很抱歉,毕业后我没有从事和项目有关的工作。”
- spring之注解
- socket编程(六)
- webpack---使用插件,常见webpack的plugin,构建vue,react单页面/多页面工程APP必备插件
- React Native 动画 ---Animated
- Spark_Streaming初级使用
- HashMap<int,String> map=new HashMap<int,String>(); 这行怎么错了?
- 计算两个非负整数的最大公约数(欧几里得算法)
- ubuntu for DP tools install
- 雅礼集训Day3-难题选讲
- 显示用户上次访问的事件