zoukankan      html  css  js  c++  java
  • 第6课.网络编程

    1.TCP和UDP的区别

    (1)TCP是面向连接的协议,UDP是面向无连接的协议。
    (2)TCP对系统资源要求较多,UDP对系统资源要求较少。
    (3)TCP是数据流模式,UDP是数据报模式。
    (4)TCP保证数据顺序及数据的正确性,UDP可能会丢包。
    

    2.简述TCP/UDP服务器端创建流程与客户端创建流程

    TCP服务器端创建流程:

    创建通信用文件描述符(socket)-->设置端口号和IP地址(为绑定做准备)-->绑定(bind)-->监听(listen)-->接受请求,建立连接(accept)-->发送与接收消息(send/recv)-->关闭文件(close)
    

    TCP客户端创建流程:

    创建通信用文件描述符(socket)-->设置端口号和IP地址-->发起连接请求(connect)-->接受与发送消息(send/recv)-->关闭文件(close)
    

    UDP服务器端创建流程:

    创建通信用文件描述符(socket)-->设置端口号和IP地址(为绑定做准备)-->绑定(bind)-->接受和发送消息(sendto && recvfrom)-->关闭文件(close)
    

    UDP客户端创建流程:

    创建通信用文件描述符(socket)-->设置端口号和IP地址-->接受与发送消息(sendto && recvfrom)-->关闭文件
    

    3.函数解析

    socket函数

    获得一个文件描述符(文件句柄)。为了执行网络输入输出,一个进程必须做的一件事就是调用socket函数获得一个文件描述符(文件句柄)
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    
    int socket(int domain, int type, int protocol);
    成功:return 费负描述符        失败:-1
        domain: 指明协议簇,目前支持5中协议簇,最常用的有AF_INET (IPv4协议)和AF_INET6 (IPv6协议)
        type  : 指明套接口类型,有3种类型可选:
                    SOCK_STREAM:字节流套接口
                    SOCK_DGRAM :数据报套接口
                    SOCK_RAW   :原始套接口;如果套接口不是原始套接口,那么第三个参数就为0
    

    bind函数

    把文件句柄和IP,端口捆绑在一起。为套接口分配一个本地IP和协议端口,对于网络协议,协议地址是32位IPv4或128位IPv6地址与16位的TCP/UDP端口的组合。如指定一个通用的通配端口为0,调用bind时内核将选择一个临时端口。如果指定一个通用通配IP地址,则要等建立连接后内核才能选择一个本地IP地址。
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    
    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    成功:0                        失败:-1
        sockfd :文件句柄
        addr   :指向特定协议的地址结构的指针
            这里不使用sockaddr这个结构体,而是使用下面这个结构体
            struct sockaddr_in { 
                short int sin_family;             /* 地址族,AF_xxx 在socket编程中只能是AF_INET */ 
                unsigned short int sin_port;      /* 端口号 (使用网络字节顺序) */ 
                struct in_addr sin_addr;          /* 存储IP地址 4字节 */ 
                unsigned char sin_zero[8];        /* 总共8个字节,实际上没有什么用,只是为了和struct sockaddr保持一样的长度,设为0就好 */ 
            }; 
        addrlen:第二个参数结构体的长度
    

    listen函数

    监听。listen函数仅被TCP服务器调用,它的作用是将用socket创建的主动套接口转换成被动套接口,并等待来自客户端的连接请求
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    
    int listen(int sockfd, int backlog);
    成功:0                        失败:-1
        sockfd :文件句柄
        backlog:最多可以一次监听多少路。这个参数规定了内核为此套接口排队的最大连接个数。由于listen函数第二个参数的原因。内核要维护两个队列。以完成连接队列和未完成连接队列。未完成队列中存放的是TCP连接的三路握手未完成的连接。accept函数是从以连接队列中取连接返回给进程,当已连接队列为空时,进程将进入睡眠状态。
    

    accept函数

    等待连接。accept函数由TCP服务器调用,从已完成连接队列头返回一个已完成连接,如果完成连接队列为空则进程进入睡眠状态
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    
    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    成功:非负描述符                失败:-1
        sockfd :文件句柄
        addr   :接收到的数据存储在这里。
        addrlen:同bind函数
    

    connect函数

    建立联系。当用connect建立了套接口后可以用connect为这个套接口指明远程端地址。如果字节流套接口(TCP),connect就使用三次握手建立一个链接。如果是数据报套接口,connect仅指明远程端地址,而不向它发送任何数据区握手。
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    
    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    成功:0                        失败:-1
    sockfd :客户端文件句柄
    addr   :见bind函数
    addrlen:同上
    

    send函数

    用来发送数据
    #include <sys/types.h>
    #include <sys/socket.h>
    
    ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    成功:返回写出的字数            失败:-1
    sockfd:文件句柄。对于服务器是accept函数返回的已连接的文件句柄。对于客户端是调研员socket函数返回的文件句柄
    buf   :指向一个用于发送信息的数据缓冲区
    len   :指明传送数据的大小
    flags :传输标志
    

    sendto函数

    用于无连接(没有connect函数)的数据报,socket方式下进行传输。由于本地socket并没有与远端服务器建立联系,所以在发送数据时应指明目的地址
    #include <sys/types.h>
    #include <sys/socket.h>
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
    成功:返回写出的字数            失败:-1
    dest_addr:用法和connect中一样
    addrlen  :同上
    

    recv函数

    用来接收数据
    #include <sys/types.h>
    #include <sys/socket.h>
    
    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    成功:返回读入的字节数            失败:-1
    参数同上
    

    recvfrom函数

    简介同sendto
    #include <sys/types.h>
    #include <sys/socket.h>
    
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);
    参数同sendto
    

    close函数

    结束传输。当所有数据操作结束后,你可以调用close函数来释放socket,从而停止改socket上的任何操作
    #include <unistd.h>
    
    int close(int fd);
    你也可以调用shutdown()函数来关闭socket。该函数允许你至停止在某个方向上的数据传输,而另一个方向上的数据传输继续进行。如你可以关闭socket的写操作而允许改socket继续接受数据直到读入所以数据。
    int shutdown(int sockfb, int how);
    成功:0                        失败:-1
    sockfb:需要关闭的socket的文件句柄。
    how   :允许shutdown操作选择
            0:不允许继续接收操作
            1:不允许继续发送操作
            3:不允许继续发送和接收操作
    

    4.代码解析

    TCP

    server.c

    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <signal.h>
    
    /*	socket
     *	bind
     *	listen
     *	accept
     *	send/recv
     */
    
    #define SERVER_PORT 8888
    #define BACKLOG     10
    
    int main(int argc, char **argv)
    {
    	int iSocketServer;
    	int iSocketClient;
    	struct sockaddr_in tSocketServerAddr;
    	struct sockaddr_in tSocketClientAddr;
    	int iRet;
    	int iAddrLen;
    
    	int iRecvLen;
    	unsigned char ucRecvBuf[1000];
    
    	int iClientNum = -1;
    
    	signal(SIGCHLD,SIG_IGN);	//防止子进程僵死
    
    	iSocketServer = socket(AF_INET, SOCK_STREAM, 0);
    	if (-1 == iSocketServer)
    	{
    		printf("socket error!
    ");
    		return -1;
    	}
    
    	tSocketServerAddr.sin_family      = AF_INET;
    	tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */
     	tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
    	memset(tSocketServerAddr.sin_zero, 0, 8);
    
    	iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
    	if (-1 == iRet)
    	{
    		printf("bind error!
    ");
    		return -1;
    	}
    
    	iRet = listen(iSocketServer, BACKLOG);
    	if (-1 == iRet)
    	{
    		printf("listen error!
    ");
    		return -1;
    	}
    
    	while (1)
    	{
    		iAddrLen = sizeof(struct sockaddr);
    		iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
    		if (-1 != iSocketClient)
    		{
    			iClientNum++;
    			printf("Get connect from client %d : %s
    ",  iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));
    			if (!fork())
    			{
    				/* 子进程的源码 */
    				while (1)
    				{
    					/* 接收客户端发来的数据并显示出来 */
    					iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);
    					if (iRecvLen <= 0)
    					{
    						close(iSocketClient);
    						return -1;
    					}
    					else
    					{
    						ucRecvBuf[iRecvLen] = '';
    						printf("Get Msg From Client %d: %s
    ", iClientNum, ucRecvBuf);
    					}
    				}				
    			}
    		}
    	}
    	
    	close(iSocketServer);
    	return 0;
    
    }
    

    client.c

    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <stdio.h>
    
    
    /*	socket
     *	connect
     *	send/recv
     */
    
    #define SERVER_PORT 8888
    
    int main(int argc, char **argv)
    {
    	int iSocketClient;
    	struct sockaddr_in tSocketServerAddr;
    	
    	int iRet;
    	unsigned char ucSendBuf[1000];
    	int iSendLen;
    
    	if (argc != 2)
    	{
    		printf("Usage:
    ");
    		printf("%s <server_ip>
    ", argv[0]);
    		return -1;
    	}
    
    	iSocketClient = socket(AF_INET, SOCK_STREAM, 0);
    
    	tSocketServerAddr.sin_family      = AF_INET;
    	tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */
    	if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
     	{
    		printf("invalid server_ip
    ");
    		return -1;
    	}
    	memset(tSocketServerAddr.sin_zero, 0, 8);
    
    
    	iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));	
    	if (-1 == iRet)
    	{
    		printf("connect error!
    ");
    		return -1;
    	}
    
    	while (1)
    	{
    		if (fgets(ucSendBuf, 999, stdin))
    		{
    			iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
    			if (iSendLen <= 0)
    			{
    				close(iSocketClient);
    				return -1;
    			}
    		}
    	}
    	
    	return 0;
    }
    

    UDP

    server.c

    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <signal.h>
    
    /* socket
     * bind
     * sendto/recvfrom
     */
    
    #define SERVER_PORT 8888
     
    int main(int argc, char **argv)
    {
    	int iSocketServer;
    	int iSocketClient;
    	struct sockaddr_in tSocketServerAddr;
    	struct sockaddr_in tSocketClientAddr;
    	int iRet;
    	int iAddrLen;
    
    	int iRecvLen;
    	unsigned char ucRecvBuf[1000];
    
    	int iClientNum = -1;
    
    	iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);
    	if (-1 == iSocketServer)
    	{
    		printf("socket error!
    ");
    		return -1;
    	}
    
    	tSocketServerAddr.sin_family	   = AF_INET;
    	tSocketServerAddr.sin_port 	   = htons(SERVER_PORT);  /* host to net, short */
    	tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
    	memset(tSocketServerAddr.sin_zero, 0, 8);
    
    	iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
    	if (-1 == iRet)
    	{
    		printf("bind error!
    ");
    		return -1;
    	}
    
    
    	while (1)
    	{
    		iAddrLen = sizeof(struct sockaddr);
    		iRecvLen = recvfrom(iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
    		if (iRecvLen > 0)
    		{
    			ucRecvBuf[iRecvLen] = '';
    			printf("Get Msg From %s : %s
    ", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);
    		}
    	}
    
    	close(iSocketServer);
    	return 0;
    }
    

    client.c

    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <stdio.h>
    
    /* socket
     * connect
     * send/recv
     */
    
    #define SERVER_PORT 8888
    
    int main(int argc, char **argv)
    {
    	int iSocketClient;
    	struct sockaddr_in tSocketServerAddr;
    	
    	int iRet;
    	unsigned char ucSendBuf[1000];
    	int iSendLen;
    
    	if (argc != 2)
    	{
    		printf("Usage:
    ");
    		printf("%s <server_ip>
    ", argv[0]);
    		return -1;
    	}
    
    	iSocketClient = socket(AF_INET, SOCK_DGRAM, 0);
    
    	tSocketServerAddr.sin_family      = AF_INET;
    	tSocketServerAddr.sin_port        = htons(SERVER_PORT);  /* host to net, short */
    	//tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
    	if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
    	{
    		printf("invalid server_ip
    ");
    		return -1;
    	}
    	memset(tSocketServerAddr.sin_zero, 0, 8);
    
    
    	iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));	
    	if (-1 == iRet)
    	{
    		printf("connect error!
    ");
    		return -1;
    	}
    
    	while (1)
    	{
    		if (fgets(ucSendBuf, 999, stdin))
    		{
    			iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
    			if (iSendLen <= 0)
    			{
    				close(iSocketClient);
    				return -1;
    			}
    		}
    	}
    	
    	return 0;
    }
  • 相关阅读:
    bzoj4513: [Sdoi2016]储能表
    bzoj4000: [TJOI2015]棋盘
    bzoj3067: Hyperdrome
    bzoj4943: [Noi2017]蚯蚓
    bzoj4044: [Cerc2014] Virus synthesis
    bzoj3676: [Apio2014]回文串
    bzoj4543: [POI2014]Hotel加强版
    bzoj1921: [Ctsc2010]珠宝商
    bzoj4754: [Jsoi2016]独特的树叶
    作图的配色
  • 原文地址:https://www.cnblogs.com/huangdengtao/p/12359005.html
Copyright © 2011-2022 走看看