recv和send函数:

#include<sys/socket.h>

ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);

ssize_t recv(int sockfd, const void *buff, size_t nbytes, int flags);

flags的值中 MSG_OOB和MSG_PEEK比较重要。

read和recv函数的区别在于:

read函数读取缓冲区的数据之后,会将缓冲区的数据删除,而recv不会删除缓冲区的数据。

因此,可以将falgs设置为MSG_PEEK,在此模式下,先查看发送过来的字符的个数,然后用read函数读取数据。

例子服务端代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<sys/wait.h> //*进程用的头文件*/
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#define MAXLINE 1024 //通信内容的最大长度 ssize_t readn(int fd, void *buf, size_t count)
{
ssize_t nleft=count;
ssize_t nread;
char *charbuf=(char*) buf; while(nleft>)
{
nread=read(fd,charbuf,nleft);
if(nread<)
{
if(errno==EINTR)
continue;
return -;
}
else if(nread==)
return count-nleft; charbuf +=nread;
nleft=count-nread;
}
return count;
} ssize_t writen(int fd, const void *buf, size_t count)
{
ssize_t nleft=count;
ssize_t nwrite;
char *charbuf=(char*) buf; while(nleft>)
{
nwrite=write(fd,charbuf,nleft);
if(nwrite<)
{
if(errno==EINTR)
continue;
return -;
}
else if(nwrite==)
return count-nleft;
charbuf +=nwrite;
nleft=count-nwrite; }
return count;
} ssize_t recv_peek(int sockfd, void *buf, size_t len)
{
int ret;
while()
{
ret=recv(sockfd,buf,len,MSG_PEEK);
if(ret==-&& errno==EINTR)
continue;
return ret;
}
} ssize_t readline(int sockfd, void *buf, size_t len)
{
ssize_t nleft=len,nread;
int ret;
char* bufchar=buf;
while()
{
ret=recv_peek(sockfd,bufchar,len);
if(ret<||ret==)
return ret;
nread=ret;
int i;
for(i=;i<nread;i++)
{
if(bufchar[i]=='\n')
{
ret=readn(sockfd,bufchar,i+);
if(ret!=i+)
exit(EXIT_FAILURE);
return ret;
}
}
if(nread>nleft)
exit(EXIT_FAILURE);
nleft-=nread;
ret=readn(sockfd,bufchar,nread);
if(ret!=nread)
exit(EXIT_FAILURE);
bufchar+=nread; }
return -; } int main()
{
int sock_fd,new_fd;//sock_fd用于监听,new_fd用于连接
struct sockaddr_in srv_addr;//服务器的地址信息
struct sockaddr_in client_addr;//客户机的地址信息
int size; //地址结构数据的长度
pid_t pid; //子进程id
ssize_t n,ret;
char buf[MAXLINE]; //用于存放通信的内容 char sendbuf[],recvbuf[];
memset(sendbuf,,sizeof(sendbuf));
memset(recvbuf,,sizeof(recvbuf)); /*创建套接字*/
sock_fd=socket(AF_INET,SOCK_STREAM,);//采用IPv4协议
if(sock_fd==-)
{
perror("creat socket failed");
exit();
} /*服务器地址参数*/
srv_addr.sin_family=AF_INET;
srv_addr.sin_port=htons();
srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
bzero(&srv_addr.sin_zero,sizeof(struct sockaddr_in));//bzero位清零函数,将sin_zero清零,sin_zero为填充字段,必须全部为零 int on=; //表示开启reuseaddr
if(setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<) //打开地址、端口重用
perror("setsockopt"); /*绑定地址和端口*/
if(bind(sock_fd,(struct sockaddr*)&srv_addr,sizeof(struct sockaddr))==-)
{
perror("bind failed");
exit();
} /*连接到服务器
if(connect(sock_fd,(struct sockaddr*)&srv_addr,sizeof(sock_fd))==-1)
{
perror("bind failed");
exit(1);
}*/ /*设置监听模式,等待客户机的监听*/
if((listen(sock_fd,))==-)
{
perror("listen failed");
exit();
} /*接受连接,采用非阻塞是的模式调用accep*/
//while(1)
//{
size=sizeof(struct sockaddr_in);
new_fd=accept(sock_fd,(struct sockaddr*)&client_addr,&size);
if(new_fd==-)
{
perror("accept failed");
//continue;//restart accept when EINTR
} printf("server:got connection from IP= %s prot= %d \n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));//连接成功,打印客户机IP地址和端口号
/*char *inet_nota(struct sockaddr_in in);
头文件:
arpa/inet.h
Winsock2.h
参数:
一个网络上的IP地址
返回值:
如果正确,返回一个字符指针,指向一块存储着点分格式IP地址的静态缓冲区(同一线程内共享此内存);错误,返回NULL。
uint31_t ntohs(uint32_t net32bitvalue);
头文件:
#include<netinet/in.h>
把net32bitvalue有网络字节序转换为主机字节序。
*/
if(send(new_fd,"Hello client,I am 192.168.229.125!\n",,)==-) //192.168.229.125为子进程IP,可更改
perror("send failed"); pid=fork(); //父进程建立套接字的连接之后,创建子进程用于通信
if(pid<)
perror("fork error\n");
if(!pid)//创建新的子进程,用于发送数据
{
// close(sock_fd);//子进程不需要监听,所以子进程关闭监
while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
{
writen(new_fd,sendbuf,strlen(sendbuf));
memset(sendbuf,,sizeof(sendbuf)); //清空,以免和下一次混淆
// exit(EXIT_SUCCESS);
}
exit(EXIT_SUCCESS);
}
//close(new_fd);//父进程不需要连接,所以关闭连接套接字
else
{
while()
{
memset(recvbuf,,sizeof(recvbuf));
ret=readline(new_fd,recvbuf,);
if(ret<)
perror("read from client error");
else if(ret==)
{
printf("peer closed\n");
break;
}
fputs(recvbuf,stdout);
}
exit(EXIT_SUCCESS);
}
//while(waitpid(-1,NULL,WNOHANG)>0);//等待子进程结束,进行新的连接
//}
return ;
}

客户端代码

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<sys/wait.h> //*进程用的头文件*/
#include<netinet/in.h>
#include<arpa/inet.h> #define MAXBYTEMUN 1024 ssize_t readn(int fd, void *buf, size_t count)
{
ssize_t nleft=count;
ssize_t nread;
char *charbuf=(char*) buf; while(nleft>)
{
nread=read(fd,charbuf,nleft);
if(nread<)
{
if(errno==EINTR)
continue;
return -;
}
else if(nread==)
return count-nleft; charbuf +=nread;
nleft=count-nread;
} return count;
} ssize_t writen(int fd, const void *buf, size_t count)
{
ssize_t nleft=count;
ssize_t nwrite;
char *charbuf=(char*) buf; while(nleft>)
{
nwrite=write(fd,charbuf,nleft);
if(nwrite<)
{
if(errno==EINTR)
continue;
return -;
}
else if(nwrite==)
return count-nleft; charbuf +=nwrite;
nleft=count-nwrite;
}
return count;
} ssize_t recv_peek(int sockfd, void *buf, size_t len)
{
int ret;
while()
{
ret=recv(sockfd,buf,len,MSG_PEEK);
if(ret==-&& errno==EINTR)
continue;
return ret;
}
} ssize_t readline(int sockfd, void *buf, size_t len)
{
ssize_t nleft=len,nread;
int ret;
char* bufchar=buf;
while()
{
ret=recv_peek(sockfd,bufchar,len);
if(ret<||ret==)
return ret;
nread=ret;
int i;
for(i=;i<nread;i++)
{
if(bufchar[i]=='\n')
{
ret=readn(sockfd,bufchar,i+);
if(ret!=i+)
exit(EXIT_FAILURE);
return ret;
}
}
if(nread>nleft)
exit(EXIT_FAILURE);
nleft-=nread;
ret=readn(sockfd,bufchar,nread);
if(ret!=nread)
exit(EXIT_FAILURE);
bufchar+=nread; }
return -; } int main(int argc,char *argv[])
{
int sock_fd,numbytes;
char buf[MAXBYTEMUN];
struct hostent *he;
struct sockaddr_in client_addr;//客户机的地址信息
ssize_t n,ret;
char recvbuf[]={''},sendbuf[]={''}; if(argc!=)
{
fprintf(stderr,"usage: client IPAddress\n"); //执行客户端程序时,输入客户端程序名称和其IP地址
exit();
} /*创建套接字*/
sock_fd=socket(AF_INET,SOCK_STREAM,);//采用IPv4协议
if(sock_fd==-)
{
perror("creat socket failed");
exit();
} /*服务器地址参数*/
client_addr.sin_family=AF_INET;
client_addr.sin_port=htons();
client_addr.sin_addr.s_addr=inet_addr(argv[]);
bzero(&client_addr.sin_zero,sizeof(struct sockaddr_in));//bzero位清零函数,将sin_zero清零,sin_zero为填充字段,必须全部为零 /*连接到服务器*/
if(connect(sock_fd,(struct sockaddr*)&client_addr,sizeof(struct sockaddr))==-)
{
perror("connect failed");
exit();
}
if((numbytes=recv(sock_fd,buf,MAXBYTEMUN,))==-)
{
perror("receive failed");
exit();
}
buf[numbytes]='\0';//在字符串末尾加上\0,否则字符串无法输出
printf("Received: %s\n",buf); pid_t pid;
pid=fork();
if(!pid)//创建新的子进程,用于接收数据
{
while()
{
memset(recvbuf,,sizeof(recvbuf));
ret=readline(sock_fd,recvbuf,);
if(ret<)
perror("read from server error");
else if(ret==)
{
printf("peer closed\n");
break;
}
fputs(recvbuf,stdout);
}
close(sock_fd);
}
else //f=父进程用于发送数据
{
//close(sock_fd);//父进程不需要连接,所以关闭连接套接字
while(fgets(sendbuf,sizeof(sendbuf),stdin)!=NULL)
{
writen(sock_fd,sendbuf,strlen(sendbuf));
memset(sendbuf,,sizeof(sendbuf)); //清空,以免和下一次混淆
}
close(sock_fd);
}
return ;
}

TCP中 recv和sendf函数的更多相关文章

  1. TCP/IP源码(59)——TCP中的三个接收队列

    http://blog.chinaunix.net/uid-23629988-id-3482647.html TCP/IP源码(59)——TCP中的三个接收队列  作者:gfree.wind@gmai ...

  2. /proc/net/tcp中各项参数说明

    /proc/net/tcp中的内容由tcp4_seq_show()函数打印,该函数中有三种打印形式,我们这里这只列出状态是TCP_SEQ_STATE_LISTENING或TCP_SEQ_STATE_E ...

  3. python socket的应用 以及tcp中的粘包现象

    1,socket套接字 一个接口模块,在tcp/udp协议之间的传输接口,将其影藏在socket之后,用户看到的是socket让其看到的. 在tcp中当做server和client的主要模块运用 #s ...

  4. SQL中Round(),Floor(),Ceiling()函数的浅析

    项目中的一个功能模块上用到了标量值函数,函数中又有ceiling()函数的用法,自己找了一些资料,对SQL中这几个函数做一个简单的记录,方便自己学习.有不足之处欢迎拍砖补充 1.round()函数遵循 ...

  5. avascript中的this与函数讲解

    徐某某 一个半路出家的野生程序员 javascript中的this与函数讲解 前言 javascript中没有块级作用域(es6以前),javascript中作用域分为函数作用域和全局作用域.并且,大 ...

  6. PHP中有关正则表达式的函数集锦

    之前学正则表达式的目的是想从网上抓取点小说啊,文档啊,还有获取相应的视频连接然后批量下载.当时初学PHP根本不知道PHP有专门抓包的工具,就像Simple_html_dom.php(在我的其他博文中有 ...

  7. SQL SERVER中用户定义标量函数(scalar user defined function)的性能问题

    用户定义函数(UDF)分类  SQL SERVER中的用户定义函数(User Defined Functions 简称UDF)分为标量函数(Scalar-Valued Function)和表值函数(T ...

  8. mysql中bit_count和bit_or函数的含义

    翻阅mysql手册时,看到有个示例使用了bit_or方法来去除重复的数据,一开始没看明白,后来看明白之后感觉非常巧妙.示例要实现的功能就是计算每月有几天有访问,先把示例摘录在这里. 1 2 3 4 5 ...

  9. TCP中的RST复位信号

    TCP中的RST复位信号 在TCP协议中RST表示复位,用来关闭异常的连接,在TCP的设计中它是不可或缺的. 发送RST包关闭连接时,不必等缓冲区的包都发出去,直接就丢弃缓存区的包发送RST包.而接收 ...

随机推荐

  1. ncdu 磁盘目录查看工具

    我平时都是直接yum -y install ncdu,但是今天失败了. 所以: 安装EPEL源 CentOS/RHEL 5 : rpm -Uvh https://dl.fedoraproject.or ...

  2. Spring-如何实现事物管理的

    事务的实现方式 实现方式共有两种:编码方式:声明式事务管理方式.基于AOP技术实现的声明式事务管理,实质就是:在方法执行前后进行拦截,然后在目标方法开始之前创建并加入事务,执行完目标方法后根据执行情况 ...

  3. Java编程思想学习(八) 内部类

    可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类的定义是简单的,但是它的语法确实很是复杂,让人不是很好理解.下面就内部类做一个小结. 一.内部类的分类 总的来讲内部类分为普通内部类,匿 ...

  4. Nginx Installation、Configuration、Rreverse Proxy、Load Balancing Learning

    目录 . Nginx简介 . Nginx安装部署 . Nginx安全配置 . Nginx反向代理实践 . Nginx负载均衡实践 1. Nginx简介 0x1: Nginx的基本特性 Nginx(&q ...

  5. ARP协议格式、ARP运行机制入门学习

    相关学习资料 http://baike.baidu.com/view/149421.htm?fromtitle=ARP%E5%8D%8F%E8%AE%AE&fromid=1742212& ...

  6. POJ 2796 Feel Good

    传送门 Time Limit: 3000MS Memory Limit: 65536K Case Time Limit: 1000MS Special Judge   Description Bill ...

  7. A.3 词法分析器

    包 lexer 是词法分析器的代码的扩展.类 Tag 定义了各个词法单元对应的常量. 1: package lexer; 2: public class Tag { 3: public final s ...

  8. MySQL逻辑备份与恢复

    备份:mysqldump -uroot -p yyzc department > /home/admin/yyzc_backup.sql 恢复:mysql -uroot -p yyzc < ...

  9. 深入分析Java Web中的中文编码问题

    要对Java Web项目进行编码原因: 1.在计算机中存储信息的最小单位是1个字节,即8个bit,所以能表示的字符范围是0~255个. 2.电脑需要表示的符号太多.无法用1个字节完全表示. 要解决这个 ...

  10. Clion = C/C++ 和 Python 共享的 IDE

    Clion + Tdmgcc + Winpython(Python)