tcp/ip通信第5期之服务器端程序

  1 /*
  2 此程序是tcp/ip通信服务器端程序,测试运行在redhat5上
  3 重构readline函数,解决粘包问题——利用“\n”识别一个消息边界
  4 */
  5
  6 #include<stdio.h>
  7 #include<netinet/in.h>
  8 #include<arpa/inet.h>
  9 #include<unistd.h>
 10 #include<fcntl.h>
 11 #include<sys/types.h>
 12 #include<sys/stat.h>
 13 #include<sys/socket.h>
 14 #include<stdio.h>
 15 #include<stdlib.h>
 16 #include<string.h>
 17 #include<signal.h>
 18 #include<errno.h>
 19
 20 ssize_t readn(int fd, void *buf, size_t count)
 21 {
 22     size_t nleft = count;//还留下多少字节没有读
 23     ssize_t nread; //已经读了多少字节
 24     char *bufp = (char *)buf;
 25     while (nleft > 0)
 26             {
 27                 if ((nread = read(fd, bufp, nleft)) < 0)
 28                 {
 29                     if (errno == EINTR)
 30  //被信号中断,errno这个全局变量的值就会等于EINTR。
 31                         continue;
 32                     return -1;
 33                 }
 34                 else if (nread == 0) //对方关闭或者已经读到eof
 35                     return count - nleft;
 36                 bufp += nread;
 37                 nleft -= nread;
 38             }
 39             return count;
 40 }
 41
 42 ssize_t writen(int fd, const void * buf, size_t count)
 43 {
 44         size_t nleft = count;
 45         ssize_t nwritten;
 46         char *bufp = (char *)buf;
 47         while (nleft > 0)
 48             {
 49                 if ((nwritten = write(fd, bufp, nleft)) < 0)
 50                 {
 51                     if (errno == EINTR)
 52                         continue;
 53  //要保证读取的字节数为指定字节数,所以继续
 54                     return -1;
 55                 }
 56                 else if (nwritten == 0)
 57                     continue;
 58  //由于其他原因引起的什么都没有写进,则继续操作,保证指定字节数
 59                 bufp += nwritten;
 60                 nleft -= nwritten;
 61             }
 62             return count;
 63 }
 64
 65 ssize_t recv_peek(int sockfd,void *buf,size_t len)
 66 {
 67     while(1)
 68     {
 69         int ret=recv(sockfd,buf,len,MSG_PEEK);
 70         if(ret==-1&&errno==EINTR)
 71             continue;
 72         return ret;
 73     }
 74 }
 75
 76 ssize_t recv_line(int sockfd,void *buf,size_t len)
 77 {
 78     int ret;//记录函数返回值
 79     int nread;//已经读到的字节数
 80     char *bufp=buf;
 81     int nleft=len;
 82     while(1)
 83     {
 84         ret=recv_peek(sockfd,bufp,nleft);
 85         if(ret<0)
 86             return ret;
 87         else if(ret==0)
 88             return ret;
 89         nread=ret;
 90         int i;
 91         for(i=0;i<nread;i++)
 92         {
 93             if(bufp[i]==‘\n‘)
 94             {
 95                 ret=readn(sockfd,bufp,i+1);
 96                 if(ret!=i+1)
 97                     exit(1);
 98                 return ret;
 99             }
100         }
101         if(nread>nleft)
102             exit(1);
103         nleft -= nread;
104         ret=readn(sockfd,bufp,nread);
105         if(ret!=nread)
106             exit(0);
107         bufp+=nread;
108     }
109     return -1;
110 }
111
112
113 #define port 5188
114 int main()
115 {
116     int listenfd;
117     //*****创建套接字*******
118     if((listenfd=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
119     /*if((listenfd=socket(PF_INET,SOCK_STREAM,0))<0)*/
120         perror("error");
121
122     //*******ipv4地址结构**********
123     struct sockaddr_in servaddr;
124     memset(&servaddr,0,sizeof(servaddr)); //清空结构体变量
125     servaddr.sin_family=AF_INET;
126     servaddr.sin_port=htons(port); //使用端口号:5188
127     servaddr.sin_addr.s_addr=htonl(INADDR_ANY);//INADDR_ANY表示使用本机的任意可用ip地址,转换成网络地址序
128     /*servaddr.sin_addr.s_addr = inet_addr("127.168.0.12");*/
129     /*inet_aton("127.168.0.12",&servaddr.sin_addr);*/
130
131     //*******绑定套接字和本机地址***********
132     //1、设置REUSEADDR选项
133     int N=1;
134     if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&N,sizeof(N))<0)
135         perror("error");
136     //2、进行绑定
137     if(bind(listenfd,(struct sockaddr*)(&servaddr),sizeof(struct sockaddr))<0)
138         perror("error");
139
140     //********将绑定的套接字转换为监听状态********
141     if(listen(listenfd,SOMAXCONN)<0) //SOMAXCONN这个宏表示最大队列值
142         perror("error");
143     /*一旦调用listen函数,那么这个套接字就变成了被动套接字(只能被动接受连接——accept,
144       不能发起连接——connect),否则还是主动套接字(可以发起连接——connect)*/
145
146     //********接收对方的连接请求**************
147     struct sockaddr_in peeraddr;  //定义对方地址
148     socklen_t peerlen=sizeof(peeraddr);
149     int con;
150     if((con=accept(listenfd,(struct sockaddr*)(&peeraddr),&peerlen))<0)
151         perror("error");
152     else
153         printf("client_ip=%s,client_port=%d\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
154
155     //*******数据通信过程***********
156     char recvbuf[1024];
157     while(1)
158     {
159         memset(recvbuf,0,sizeof(recvbuf));
160         int ret=recv_line(con,recvbuf,sizeof(recvbuf));//con这里是已连接套接字,不再是被动套接字,而是主动套接字了
161         if(ret==-1)
162             exit(1);
163         if(ret==0)
164         {
165             printf("client_port is closed.\n");
166             break;
167         }
168         fputs(recvbuf,stdout);
169         writen(con,recvbuf,strlen(recvbuf));
170         memset(recvbuf,0,sizeof(recvbuf));
171     }
172     close(con);
173     close(listenfd);
174     return 0;
175
176 }
时间: 2024-08-01 20:20:06

tcp/ip通信第5期之服务器端程序的相关文章

tcp/ip通信第5期之客户机端程序

1 /*此程序是tcp/ip通信的客户机端程序, 2 测试运行在redhat6系统上 3 重构readline函数,解决粘包问题——利用“\n”识别一个消息边界 4 */ 5 #include<stdio.h> 6 #include<stdlib.h> 7 #include<unistd.h> 8 #include<sys/types.h> 9 #include<sys/socket.h> 10 #include<arpa/inet.h&g

使用Boost asio实现同步的TCP/IP通信

可以先了解一下Boost asio基本概念,以下是Boost asio实现的同步TCP/IP通信: 服务器程序部分,如果想保留套接字之后继续通信,可以动态申请socket_type,保存指针,因为socket_type貌似不能拷贝: #include "stdafx.h" #include <iostream> #include <boost/asio.hpp> using namespace boost::asio; using namespace std;

NET使用SuperSocket完成TCP/IP通信(记录篇)

1)为什么使用SuperSocket? 性能高,易上手.有中文文档,我们可以有更多的时间用在业务逻辑上,SuperSocket有效的利用自己的协议解决粘包 2)SuperSocket的协议内容? 命令 body  列如:TestCommand 1 2 3)怎样在Net下使用 SuperSocket? 1)新建项目命名为SuperSocketWeb 2)引用程序集->NuGet工具搜索安装SuperSocket,SuperSocket.Engine两个组件 3)下载测试工具SocketTool 官

TCP/IP之四书五经[转自2003.12程序员]

TCP/IP协议是当前广域网和局域网通用的网络协议,因此,基于TCP/IP的编程就格外重要.从应用上来说,现在直接利用C层次Socket API进行TCP/IP编程的人确实越来越少了,各种现成的框架(如ACE.Java..NET FCL)和控件(如IP*Works)大大简化了TCP/IP编程的难度.但是,如果想要在这个领域达到融会贯通的地步,不打下坚实的基础是不可想象的.正如Richard Stevens在TCP/IP Illustrated中所说,在网络编程领域,开发者所遇到的实际问题中,大约

TCP/IP通信实现

网络层的IP协议提供不可靠通信服务.TCP协议则解决了分组的重传和排序问题. TCP通信特征 : 1)全双工,同时发送和接收数据 2)只支持两个端口之间的通信 3)基于字节流.对端无法知道报文的边界.例如发送4个512字节的数据,接收方并不清楚是4个512或是2个1024 TCP通信流程 来自为知笔记(Wiz)

一个TCP/IP通信的实例

1 /*服务器端*/ 2 #include<stdlib.h> 3 #include<stdio.h> 4 #include<string.h> 5 #include<errno.h> 6 #include<netdb.h> 7 #include<sys/types.h> 8 #include<netinet/in.h> 9 #include<sys/socket.h> 10 #include<unist

TCP/IP通信过程

一.参考网址 二.TCP 1.例子: 192.168.22.66 telenet到192.168.22.74的tcp建立过程 1)SYN: 2)SYN+ACK 3)ACK 原文地址:https://www.cnblogs.com/shanyu20/p/11770436.html

Java 网络编程(五) 使用TCP/IP的套接字(Socket)进行通信

套接字Socket的引入 为了能够方便地开发网络应用软件,由美国伯克利大学在Unix上推出了一种应用程序访问通信协议的操作系统用调用socket(套接字). socket的出现,使程序员可以很方便地访问TCP/IP,从而开发各种网络应用的程序. 随着Unix的应用推广,套接字在编写网络软件中得到了极大的普及.后来,套接字又被引进了Windows等操作系统中.Java语言也引入了套接字编程模型. 什么是Socket? Socket是连接运行在网络上的两个程序间的双向通讯的端点. 使用Socket进

TCP/IP基础概念及通信过程举例

TCP/IP基础概念及通信过程举例 出现 上个世纪60年代,由于中央集中式网络的容灾性较弱,以美国国防部为中心的一家组织研究出分组交换网络.后来为了验证分组交换技术的实用性,ARPANET出现了,并且在3年内逐渐发展,由4个节点发展至34个节点.20世纪70年代前半叶,ARPANET一个机构研制出了TCP/IP,1982年具体规范确定,1983年成为ARPANET唯一指定协议.乘着TCP/IP的发展之风,互联网应运而生. 标准化 先说明一下TCP/IP的含义.其实它是指利用IP进行通信是所用到的