流式套接字(TCP)是面向流的,也就是应用层看到的所有数据是一个流,没有消息保护边界,应用层并不能从这一整个流中区分出每一包数据。例如发送方发送了三次“hello!”,接收方在发送方发完三次数据后在进行读取,那么在接收方缓冲区足够大的情况下read一次会读出来”hello!hello!hello!“,即发送方发了三次数据,但是接收方一次就都接收了,接收方并不知道发送方是发送了三次数据,并且也不知道这三次分别发的什么。所以一般用tcp的话,需要应用层自己定义一套协议来划分出一个数据包的内容,例如加包头包尾标志,增加两字节的数据包长度等。
数据报套接字(UDP)是面向数据报的,有消息保护边界,因为有了消息保护边界,所以它并不把所有消息看成一个整体,而是可以根据保护边界划分出每一个包的内容,例如发送方发送了三次”hello!“,接收方在发送方发完三次数据后在进行读取,接收方并不会调用一次read就读出”hello!hello!hello!“,而是read三次,每次都读出”hello!“,说明数据报套接字是根据消息边界将单独的每一次数据返回给应用层。
tcp测试
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/un.h>
#define SA struct sockaddr
#define SEND_PATH "/tmp/d.udp" //运行一次程序要把这个文件删除在运行,否则bind失败
#define RECV_PATH "/tmp/s.udp" //运行一次程序要把这个文件删除在运行,否则bind失败
void sendmesg()
{
char buf[128] = "hello!";
struct sockaddr_un severAddr, clientAddr;
int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("socket");
return;
}
bzero(&severAddr, sizeof(severAddr));
severAddr.sun_family = AF_LOCAL;
snprintf(severAddr.sun_path, sizeof(severAddr.sun_path), SEND_PATH);
if(bind(sockfd, (SA*)&severAddr, sizeof(severAddr)) < 0)
{
perror("bind");
return;
}
bzero(&clientAddr, sizeof(clientAddr));
clientAddr.sun_family = AF_LOCAL;
snprintf(clientAddr.sun_path, sizeof(clientAddr.sun_path), RECV_PATH);
if(connect(sockfd, (SA