网络编程5--UDP通信和本地套接字

 UDP实现的并发服务器和客户端

    TCP:  面向连接的,可靠数据包传输。对于不稳定的网络层,采取完全弥补的通信方式。 丢包重传。

       优点:

           稳定。    

              数据流量稳定、速度稳定、顺序

       缺点:

           传输速度慢。相率低。开销大。

       使用场景:数据的完整型要求较高,不追求效率。

             大数据传输、文件传输。

    UDP:  无连接的,不可靠的数据报传递。对于不稳定的网络层,采取完全不弥补的通信方式。 默认还原网络状况

       优点:

           传输速度快。相率高。开销小。

       缺点:

           不稳定。

              数据流量。速度。顺序。

       使用场景:对时效性要求较高场合。稳定性其次。

             游戏、视频会议、视频电话。       腾讯、华为、阿里  ---  应用层数据校验协议,弥补udp的不足。

基于UDP的CS模型

	recv()/send() 只能用于 TCP 通信。 替代 read、write

	accpet(); ---- Connect(); ---被舍弃

	server:

		lfd = socket(AF_INET, STREAM, 0);	SOCK_DGRAM --- 报式协议。

		bind();

		listen();  --- 可有可无

		while(1){

			read(cfd, buf, sizeof) --- 被替换 --- recvfrom() --- 涵盖accept传出地址结构。
小-- 大
				
			write();--- 被替换 --- sendto()---- connect
		}
		close();

client:

		connfd = socket(AF_INET, SOCK_DGRAM, 0);

		sendto(‘服务器的地址结构’, 地址结构大小)

		recvfrom()

		写到屏幕

		close();

recvfrom和sendto函数

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

					sockfd: 套接字

					buf:缓冲区地址

					len:缓冲区大小

					flags: 0

					src_addr:(struct sockaddr *)&addr 传出。 对端地址结构

					addrlen:传入传出。

				返回值: 成功接收数据字节数。 失败:-1 errn。 0: 对端关闭。



ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

					sockfd: 套接字

					buf:存储数据的缓冲区

					len:数据长度

					flags: 0

					src_addr:(struct sockaddr *)&addr 传入。 目标地址结构

					addrlen:地址结构长度。

				返回值:成功写出数据字节数。 失败 -1, errno	

sever端

#include <string.h>  
#include <stdio.h>  
#include <unistd.h>  
#include <arpa/inet.h>  
#include <ctype.h>  
  
#define SERV_PORT 8000  
  
int main(void)  
{  
    struct sockaddr_in serv_addr, clie_addr;  
    socklen_t clie_addr_len;  
    int sockfd;  
    char buf[BUFSIZ];  
    char str[INET_ADDRSTRLEN];  
    int i, n;  
  
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);  
  
    bzero(&serv_addr, sizeof(serv_addr));  
    serv_addr.sin_family = AF_INET;  
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  
    serv_addr.sin_port = htons(SERV_PORT);  
  
    bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));  
  
    printf("Accepting connections ...\n");  
    while (1) {  
        clie_addr_len = sizeof(clie_addr);  
        n = recvfrom(sockfd, buf, BUFSIZ,0, (struct sockaddr *)&clie_addr, &clie_addr_len);  
        if (n == -1)  
            perror("recvfrom error");  
  
        printf("received from %s at PORT %d\n",  
                inet_ntop(AF_INET, &clie_addr.sin_addr, str, sizeof(str)),  
                ntohs(clie_addr.sin_port));  
  
        for (i = 0; i < n; i++)  
            buf[i] = toupper(buf[i]);  
  
        n = sendto(sockfd, buf, n, 0, (struct sockaddr *)&clie_addr, sizeof(clie_addr));  
        if (n == -1)  
            perror("sendto error");  
    }  
  
    close(sockfd);  
  
    return 0;  
} 

client端

#include <stdio.h>  
#include <string.h>  
#include <unistd.h>  
#include <arpa/inet.h>  
#include <ctype.h>  
  
#define SERV_PORT 8000  
  
int main(int argc, char *argv[])  
{  
    struct sockaddr_in servaddr;  
    int sockfd, n;  
    char buf[BUFSIZ];  
  
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);  
  
    bzero(&servaddr, sizeof(servaddr));  
    servaddr.sin_family = AF_INET;  
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);  
    servaddr.sin_port = htons(SERV_PORT);  
  
    bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));  
  
    while (fgets(buf, BUFSIZ, stdin) != NULL) {  
        n = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));  
        if (n == -1)  
            perror("sendto error");  
  
        n = recvfrom(sockfd, buf, BUFSIZ, 0, NULL, 0);         //NULL:不关心对端信息  
        if (n == -1)  
            perror("recvfrom error");  
  
        write(STDOUT_FILENO, buf, n);  
    }  
  
    close(sockfd);  
  
    return 0;  
}

由于UDP不需要建立连接,所以直接就是高并发服务器

本地套接字

本地套接字:

	IPC: pipe、fifo、mmap、信号、本地套(domain)--- CS模型


	对比网络编程 TCP C/S模型, 注意以下几点:

	1. int socket(int domain, int type, int protocol); 参数 domain:AF_INET --> AF_UNIX/AF_LOCAL 
	
							     type: SOCK_STREAM/SOCK_DGRAM  都可以。	
	2. 地址结构:  sockaddr_in --> sockaddr_un

		struct sockaddr_in srv_addr; --> struct sockaddr_un srv_adrr;

		srv_addr.sin_family = AF_INET;  --> srv_addr.sun_family = AF_UNIX;
·
		srv_addr.sin_port = htons(8888);    strcpy(srv_addr.sun_path, "srv.socket")

		srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);			len = offsetof(struct sockaddr_un, sun_path) + strlen("srv.socket");
	
		bind(fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));  --> 	bind(fd, (struct sockaddr *)&srv_addr, len); 


	3. bind()函数调用成功,本地套接字会创建一个 socket。因此为保证bind成功,通常我们在 bind之前, 可以使用 unlink("srv.socket");


	4. 客户端不能依赖 “隐式绑定”。并且应该在通信建立过程中,创建且初始化2个地址结构:

		1) client_addr --> bind()

		2)  server_addr --> connect();

sever端

#include <stdio.h>  
#include <unistd.h>  
#include <sys/socket.h>  
#include <strings.h>  
#include <string.h>  
#include <ctype.h>  
#include <arpa/inet.h>  
#include <sys/un.h>  
#include <stddef.h>  
  
#include "wrap.h"  
  
#define SERV_ADDR  "serv.socket"  
  
int main(void)  
{  
    int lfd, cfd, len, size, i;  
    struct sockaddr_un servaddr, cliaddr;  
    char buf[4096];  
  
    lfd = Socket(AF_UNIX, SOCK_STREAM, 0);  
  
    bzero(&servaddr, sizeof(servaddr));  
    servaddr.sun_family = AF_UNIX;  
    strcpy(servaddr.sun_path, SERV_ADDR);  
  
    len = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path);     /* servaddr total len */  
  
    unlink(SERV_ADDR);                              /* 确保bind之前serv.sock文件不存在,bind会创建该文件 */  
    Bind(lfd, (struct sockaddr *)&servaddr, len);           /* 参3不能是sizeof(servaddr) */  
  
    Listen(lfd, 20);  
  
    printf("Accept ...\n");  
    while (1) {  
        len = sizeof(cliaddr);  //AF_UNIX大小+108B  
  
        cfd = Accept(lfd, (struct sockaddr *)&cliaddr, (socklen_t *)&len);  
  
        len -= offsetof(struct sockaddr_un, sun_path);      /* 得到文件名的长度 */  
        cliaddr.sun_path[len] = '\0';                       /* 确保打印时,没有乱码出现 */  
  
        printf("client bind filename %s\n", cliaddr.sun_path);  
  
        while ((size = read(cfd, buf, sizeof(buf))) > 0) {  
            for (i = 0; i < size; i++)  
                buf[i] = toupper(buf[i]);  
            write(cfd, buf, size);  
        }  
        close(cfd);  
    }  
    close(lfd);  
  
    return 0;  
} 

client端

#include <stdio.h>  
#include <unistd.h>  
#include <sys/types.h>           
#include <sys/socket.h>  
#include <strings.h>  
#include <string.h>  
#include <ctype.h>  
#include <arpa/inet.h>  
#include <sys/un.h>  
#include <stddef.h>  
  
#include "wrap.h"  
  
#define SERV_ADDR "serv.socket"  
#define CLIE_ADDR "clie.socket"  
  
int main(void)  
{  
    int  cfd, len;  
    struct sockaddr_un servaddr, cliaddr;  
    char buf[4096];  
  
    cfd = Socket(AF_UNIX, SOCK_STREAM, 0);  
  
    bzero(&cliaddr, sizeof(cliaddr));  
    cliaddr.sun_family = AF_UNIX;  
    strcpy(cliaddr.sun_path,CLIE_ADDR);  
  
    len = offsetof(struct sockaddr_un, sun_path) + strlen(cliaddr.sun_path);     /* 计算客户端地址结构有效长度 */  
  
    unlink(CLIE_ADDR);  
    Bind(cfd, (struct sockaddr *)&cliaddr, len);                                 /* 客户端也需要bind, 不能依赖自动绑定*/  
  
      
    bzero(&servaddr, sizeof(servaddr));                                          /* 构造server 地址 */  
    servaddr.sun_family = AF_UNIX;  
    strcpy(servaddr.sun_path, SERV_ADDR);  
  
    len = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path);   /* 计算服务器端地址结构有效长度 */  
  
    Connect(cfd, (struct sockaddr *)&servaddr, len);  
  
    while (fgets(buf, sizeof(buf), stdin) != NULL) {  
        write(cfd, buf, strlen(buf));  
        len = read(cfd, buf, sizeof(buf));  
        write(STDOUT_FILENO, buf, len);  
    }  
  
    close(cfd);  
  
    return 0;  
}  

本地套接字和网络套接字对比

网络套接字                        本地套接字

    server:    lfd = socket(AF_INET, SOCK_STREAM, 0);            lfd = socket(AF_UNIX, SOCK_STREAM, 0);
        
            bzero() ---- struct sockaddr_in serv_addr;        bzero() ---- struct sockaddr_un serv_addr, clie_addr;

            serv_addr.sin_family = AF_INET;                serv_addr.sun_family = AF_UNIX;    
            serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
            serv_addr.sin_port = htons(8888);            strcpy(serv_addr.sun_path, "套接字文件名")
                                        len = offsetof(sockaddr_un, sun_path) + strlen();

                                        
            bind(lfd, (struct sockaddr *)&serv_addr, sizeof());    unlink("套接字文件名");
                                        bind(lfd, (struct sockaddr *)&serv_addr, len);  创建新文件

            Listen(lfd, 128);                    Listen(lfd, 128);

            cfd = Accept(lfd, ()&clie_addr, &len);            cfd = Accept(lfd, ()&clie_addr, &len);  


    client:        
            lfd = socket(AF_INET, SOCK_STREAM, 0);            lfd = socket(AF_UNIX, SOCK_STREAM, 0);

            " 隐式绑定 IP+port"                    bzero() ---- struct sockaddr_un clie_addr;
                                        clie_addr.sun_family = AF_UNIX;
                                        strcpy(clie_addr.sun_path, "client套接字文件名")
                                        len = offsetof(sockaddr_un, sun_path) + strlen();
                                        unlink( "client套接字文件名");
                                        bind(lfd, (struct sockaddr *)&clie_addr, len);

            bzero() ---- struct sockaddr_in serv_addr;        bzero() ---- struct sockaddr_un serv_addr;

            serv_addr.sin_family = AF_INET;                serv_addr.sun_family = AF_UNIX;
                                                                    
            inet_pton(AF_INT, "服务器IP", &sin_addr.s_addr)                            
                                        strcpy(serv_addr.sun_path, "server套接字文件名")
            serv_addr.sin_port = htons("服务器端口");        
                                        
                                        len = offsetof(sockaddr_un, sun_path) + strlen();

            connect(lfd, &serv_addr, sizeof());            connect(lfd, &serv_addr, len);

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值