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>
 11 #include<netinet/in.h>
 12 #include<string.h>
 13 #include<signal.h>
 14 #include<errno.h>
 15 
 16 #define port 5188
 17 
 18 ssize_t readn(int fd, void *buf, size_t count)
 19 {
 20     size_t nleft = count;//还留下多少字节没有读
 21     ssize_t nread; //已经读了多少字节
 22     char *bufp = (char *)buf;
 23     while (nleft > 0)
 24             {
 25                 if ((nread = read(fd, bufp, nleft)) < 0)
 26                 {
 27                     if (errno == EINTR)
 28  //被信号中断,errno这个全局变量的值就会等于EINTR。
 29                         continue;
 30                     return -1;
 31                 }
 32                 else if (nread == 0) //对方关闭或者已经读到eof
 33                     return count - nleft;
 34                 bufp += nread;
 35                 nleft -= nread;
 36             }
 37             return count;
 38 }
 39      
 40 ssize_t writen(int fd, const void * buf, size_t count) 
 41 {
 42         size_t nleft = count;
 43         ssize_t nwritten;
 44         char *bufp = (char *)buf;
 45         while (nleft > 0)
 46             {
 47                 if ((nwritten = write(fd, bufp, nleft)) < 0)
 48                 {
 49                     if (errno == EINTR)
 50                         continue;
 51  //要保证读取的字节数为指定字节数,所以继续
 52                     return -1;
 53                 }
 54                 else if (nwritten == 0)        
 55                     continue;
 56  //由于其他原因引起的什么都没有写进,则继续操作,保证指定字节数
 57                 bufp += nwritten;
 58                 nleft -= nwritten;
 59             }
 60             return count;
 61 }
 62 
 63 ssize_t recv_peek(int sockfd,void *buf,size_t len)
 64 {
 65     while(1)
 66     {
 67         int ret=recv(sockfd,buf,len,MSG_PEEK);
 68         if(ret==-1&&errno==EINTR)
 69             continue;
 70         return ret;
 71     }
 72 }
 73 
 74 ssize_t recv_line(int sockfd,void *buf,size_t len)
 75 {
 76     int ret;//记录函数返回值
 77     int nread;//已经读到的字节数
 78     char *bufp=buf;
 79     int nleft=len;
 80     while(1)
 81     {
 82         ret=recv_peek(sockfd,bufp,nleft);
 83         if(ret<0)
 84             return ret;
 85         else if(ret==0)
 86             return ret;
 87         nread=ret;
 88         int i;
 89         for(i=0;i<nread;i++)
 90         {
 91             if(bufp[i]=='\n')
 92             {
 93                 ret=readn(sockfd,bufp,i+1);
 94                 if(ret!=i+1)
 95                     exit(1);
 96                 return ret;
 97             }
 98         }
 99         if(nread>nleft)
100             exit(1);
101         nleft -= nread;
102         ret=readn(sockfd,bufp,nread);
103         if(ret!=nread)
104             exit(0);
105         bufp+=nread;
106     }
107     return -1;
108 }
109 
110 int main()
111 {
112     int sock;
113     //*****创建套接字*******
114     if((sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
115     /*if((listenfd=socket(PF_INET,SOCK_STREAM,0))<0)*/
116         perror("error");
117         
118     //*******ipv4地址结构**********
119     struct sockaddr_in servaddr;
120     memset(&servaddr,0,sizeof(servaddr)); //清空结构体变量
121     servaddr.sin_family=AF_INET;
122     servaddr.sin_port= htons(port); //使用端口号:5188
123     servaddr.sin_addr.s_addr=inet_addr("192.168.248.129");  //ip地址使用对方的地址,即服务器地址
124     printf("the port_id:%d\n",port);
125     
126     //*********连接请求************
127     if(connect(sock,(struct sockaddr*)(&servaddr),sizeof(servaddr))<0)  //使用对方的ip地址
128         perror("error");
129     else
130         printf("connected success.\n");
131     
132     //************通信过程*************
133     char sendbuf[1024]={0};
134     char recvbuf[1024]={0};
135     while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
136     {
137         writen(sock,sendbuf,strlen(sendbuf));
138         int ret=recv_line(sock,recvbuf,sizeof(recvbuf));
139         if(ret==-1)
140             perror("error\n");
141         if(ret==0)
142         {
143             printf("peer is closed.\n");
144             break;
145         }
146         
147         fputs(recvbuf,stdout);
148         memset(sendbuf,0,sizeof(sendbuf)); //清空缓存
149         memset(recvbuf,0,sizeof(recvbuf));
150     }
151     close(sock);
152     return 0;
153 }

 

posted @ 2015-09-17 11:37  e-data  阅读(157)  评论(0编辑  收藏  举报