/*此程序是tcp/ip通信的客户机端程序,
测试运行在redhat6系统上
重构readline函数,解决粘包问题——利用“\n”识别一个消息边界
*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<signal.h>
#include<errno.h> #define port 5188 ssize_t readn(int fd, void *buf, size_t count)
{
size_t nleft = count;//还留下多少字节没有读
ssize_t nread; //已经读了多少字节
char *bufp = (char *)buf;
while (nleft > )
{
if ((nread = read(fd, bufp, nleft)) < )
{
if (errno == EINTR)
//被信号中断,errno这个全局变量的值就会等于EINTR。
continue;
return -;
}
else if (nread == ) //对方关闭或者已经读到eof
return count - nleft;
bufp += nread;
nleft -= nread;
}
return count;
} ssize_t writen(int fd, const void * buf, size_t count)
{
size_t nleft = count;
ssize_t nwritten;
char *bufp = (char *)buf;
while (nleft > )
{
if ((nwritten = write(fd, bufp, nleft)) < )
{
if (errno == EINTR)
continue;
//要保证读取的字节数为指定字节数,所以继续
return -;
}
else if (nwritten == )
continue;
//由于其他原因引起的什么都没有写进,则继续操作,保证指定字节数
bufp += nwritten;
nleft -= nwritten;
}
return count;
} ssize_t recv_peek(int sockfd,void *buf,size_t len)
{
while()
{
int ret=recv(sockfd,buf,len,MSG_PEEK);
if(ret==-&&errno==EINTR)
continue;
return ret;
}
} ssize_t recv_line(int sockfd,void *buf,size_t len)
{
int ret;//记录函数返回值
int nread;//已经读到的字节数
char *bufp=buf;
int nleft=len;
while()
{
ret=recv_peek(sockfd,bufp,nleft);
if(ret<)
return ret;
else if(ret==)
return ret;
nread=ret;
int i;
for(i=;i<nread;i++)
{
if(bufp[i]=='\n')
{
ret=readn(sockfd,bufp,i+);
if(ret!=i+)
exit();
return ret;
}
}
if(nread>nleft)
exit();
nleft -= nread;
ret=readn(sockfd,bufp,nread);
if(ret!=nread)
exit();
bufp+=nread;
}
return -;
} int main()
{
int sock;
//*****创建套接字*******
if((sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<)
/*if((listenfd=socket(PF_INET,SOCK_STREAM,0))<0)*/
perror("error"); //*******ipv4地址结构**********
struct sockaddr_in servaddr;
memset(&servaddr,,sizeof(servaddr)); //清空结构体变量
servaddr.sin_family=AF_INET;
servaddr.sin_port= htons(port); //使用端口号:5188
servaddr.sin_addr.s_addr=inet_addr("192.168.248.129"); //ip地址使用对方的地址,即服务器地址
printf("the port_id:%d\n",port); //*********连接请求************
if(connect(sock,(struct sockaddr*)(&servaddr),sizeof(servaddr))<) //使用对方的ip地址
perror("error");
else
printf("connected success.\n"); //************通信过程*************
char sendbuf[]={};
char recvbuf[]={};
while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
{
writen(sock,sendbuf,strlen(sendbuf));
int ret=recv_line(sock,recvbuf,sizeof(recvbuf));
if(ret==-)
perror("error\n");
if(ret==)
{
printf("peer is closed.\n");
break;
} fputs(recvbuf,stdout);
memset(sendbuf,,sizeof(sendbuf)); //清空缓存
memset(recvbuf,,sizeof(recvbuf));
}
close(sock);
return ;
}
04-19 23:14
查看更多