linux网络编程-UDP套接字通信实验,注意和上一篇文章的区分(TCP编程)

代码分析 client.c

  程序分析client.c

//client.c
//
//  UDP 套接字编程典型模型
//
//		客户端							服务器端
//	创建套接字(socket)				创建套接字(socket)
//									绑定服务器地址和端口(bind)
//	客户端发送请求(sendto)	---->	接收客户端请求(recvfrom)
//	客户端接收响应(recvfrom)<----	回送响应(sendto)
//	关闭套接字(close)
//man 7 socket
//accept() , bind() , connect() ,  getsockname()  ,  getsockopt()  ,
//listen()  , recv() , recvfrom() , recvmsg() , send() , sendmsg() ,
//sendto() , setsockopt() , shutdown() , socket() , socketpair() 
//
//socket - create an endpoint for communication
//#include <sys/socket.h>
//int socket(int domain, int type, int protocol);
//RETURN VALUE
//Upon successful completion, socket() shall return  a  non-negative
//integer,  the  socket  file  descriptor.  Otherwise, a value of -1
//shall be returned and errno set to indicate the error.
//
//bind - bind a name to a socket
//#include <sys/socket.h>
//int bind(int socket, const struct sockaddr *address,
//        socklen_t address_len);
//RETURN VALUE
//Upon  successful  completion, bind() shall return 0; otherwise, -1
//shall be returned and errno set to indicate the error.
//
//listen  -  listen  for  socket  connections  and limit the queue of
//incoming connections
//#include <sys/socket.h>
//int listen(int socket, int backlog);
//RETURN VALUE
//Upon successful completions, listen() shall return 0; otherwise, -1
//shall be returned and errno set to indicate the error.
//
//connect - connect a socket
//#include <sys/socket.h>
//int connect(int socket, const struct sockaddr *address,
//            socklen_t address_len);
//RETURN VALUE
//Upon successful completion, connect() shall return 0; otherwise, -1
//shall be returned and errno set to indicate the error.
//
//accept - accept a new connection on a socket
//#include <sys/socket.h>
//int accept(int socket, struct sockaddr *restrict address,
//          socklen_t *restrict address_len);
//RETURN VALUE
//Upon  successful completion, accept() shall return the non-negative
//file descriptor of the accepted  socket.  Otherwise,  -1  shall  be
//returned and errno set to indicate the error.
//
//send, sendto, sentmsg  - send a message on a socket
//#include <sys/socket.h>
//ssize_t  send(int  socket,  const  void *buffer, size_t length, int
//flags);
//ssize_t sendto(int socket, const void *message, size_t length,
//    int flags, const struct sockaddr *dest_addr,socklen_t dest_len);
//ssize_t  sendmsg(int  socket,  const  struct  msghdr  *message, int
//flags);
//RETURN VALUE
//Upon successful completion, shall return the number of bytes
//sent. Otherwise, -1 shall be returned and errno set to indicate the
//error.
//
//recv, recvfrom, recvmsg - receive a message from a socket
//#include <sys/types.h>
//#include <sys/socket.h>
//ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//
//ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
//                struct sockaddr *src_addr, socklen_t *addrlen);
//
//ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
//RETURN VALUE
//These  calls return the number of bytes received, or -1 if an error
//occurred. The  return value will be 0 when the peer has performed an
//orderly shutdown.
//
//struct iovec {                    /* Scatter/gather array items */
//    void  *iov_base;              /* Starting address */
//    size_t iov_len;               /* Number of bytes to transfer */
//};
//
//struct msghdr {
//    void         *msg_name;       /* optional address */
//    socklen_t     msg_namelen;    /* size of address */
//    struct iovec *msg_iov;        /* scatter/gather array */
//    size_t        msg_iovlen;     /* # elements in msg_iov */
//    void         *msg_control;    /* ancillary data, see below */
//    size_t        msg_controllen; /* ancillary data buffer len */
//    int           msg_flags;      /* flags on received message */
//};
//
//socketpair - create a pair of connected sockets
//#include <sys/socket.h>
//int socketpair(int domain, int type, int protocol,
//                            int socket_vector[2]);
//RETURN VALUE
//Upon  successful  completion,  this function shall return 0; 
//otherwise, -1 shall be returned and errno set to indicate the error.
//
//setsockopt - set the socket options
//#include <sys/socket.h>
//int setsockopt(int socket, int level, int option_name,
//               const void *option_value, socklen_t option_len);
//RETURN VALUE
//Upon successful completion, setsockopt() shall return 0. 
//Otherwise, -1 shall be returned and errno set to indicate the error.
//
//getsockopt - get the socket options
//#include <sys/socket.h>
//int getsockopt(int socket, int level, int option_name,
//    void *restrict option_value, socklen_t *restrict option_len);
//RETURN VALUE
//Upon successful completion, getsockopt() shall return 0; 
//otherwise, -1 shall be returned and errno set to indicate the error.
//
//getsockname - get the socket name
//#include <sys/socket.h>
//int getsockname(int socket, struct sockaddr *restrict address,
//                socklen_t *restrict address_len);
//RETURN VALUE
//Upon successful completion, 0 shall be returned, the address argu‐
//ment shall point to the address of the socket, and the address_len
//argument  shall point to the length of the address.  Otherwise, -1
//shall be returned and errno set to indicate the error.
//
//shutdown - shut down socket send and receive operations
//#include <sys/socket.h>
//int shutdown(int socket, int how);
//how    Specifies the type of shutdown. The values are as follows:
//SHUT_RD		Disables further receive operations.
//SHUT_WR		Disables further send operations.
//SHUT_RDWR		Disables further send and receive operations.
//RETURN VALUE
//Upon  successful completion, shutdown() shall return 0; otherwise,
//-1 shall be returned and errno set to indicate the error.
//
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>

#define PORT	8000
#define BUF_SIZE	1024

int main(int argc, char *argv[])
{
	struct sockaddr_in *sin_addrptr;
	struct sockaddr serv_sa;
	struct addrinfo *serv_aiptr, hints, *res_aiptr ;
	int sockfd, res;
	char buf[BUF_SIZE];
	char serv_name[80];

	memset(serv_name, 0, sizeof(serv_name));
	strcpy(serv_name, "127.0.0.1");

	if (argc > 1)
	{
		memset(serv_name, 0, sizeof(serv_name));
		strcpy(serv_name, argv[1]);
	}

	//服务起地址解析函数getaddrinfo
	//int getaddrinfo(const char *node, const char *service,           
	//                const struct addrinfo *hints,
	//                struct addrinfo **res);
	memset(&hints, 0, sizeof(hints));
	hints.ai_flags = AI_PASSIVE;
	hints.ai_family = AF_INET;
	
	if((res = getaddrinfo(serv_name, NULL, &hints, &res_aiptr)) !=0)
	{
		fprintf(stderr, "Error getaddrinfo %s\n",gai_strerror(res));
		exit(-1);
	}
	for(serv_aiptr = res_aiptr;serv_aiptr != NULL; serv_aiptr++)
	{
		if(serv_aiptr->ai_family == AF_INET)
		{
			serv_sa = *(serv_aiptr->ai_addr);
			sin_addrptr = (struct sockaddr_in *) &serv_sa;
			break;
		}
	}
	if (serv_aiptr == NULL)
	{
		freeaddrinfo(res_aiptr);
		printf("不能发现服务器");
		exit(-1);
	}
	freeaddrinfo(res_aiptr);

	//建立socket连接
	//int socket(int domain, int type, int protocol);
	//以默认协议,在INET域建立数据流套接字
	if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	{
		perror("Error socket");
		exit(-1);
	}
	printf("套接字 ID = %d\n", sockfd);
	
	//设置服务器sockaddr_in 结构体相关参数
	sin_addrptr->sin_port = htons(PORT);

	while(1)
	{
		memset(buf, 0, sizeof(buf));
		fgets(buf, sizeof(buf), stdin);

		//发送消息到服务器端
		//ssize_t sendto(int socket, const void *message, 
		//	size_t length, int flags,
		//	const struct sockaddr *dest_addr,socklen_t dest_len);
		if ((sendto(sockfd, buf, strlen(buf), 0, \
						&serv_sa, sizeof(serv_sa))) == -1)
		{
			perror("Error send");
			exit(-1);
		}

		//接收服务器端发送的消息
		memset(buf, 0, sizeof(buf));
		//ssize_t recvfrom(int sockfd, void *buf, size_t len,
		//int flags, struct sockaddr *src_addr, socklen_t *addrlen);
		if ((res = recvfrom(sockfd, buf, sizeof(buf),\
						0, NULL, NULL)) == -1)
		{
			perror("Error recv");
			exit(-1);
		}
		printf("接收到服务器信息:%s(%d个字节)\n", buf, res);
	}
	close(sockfd);
	exit(0);
}

代码分析 server.c

  程序分析server.c

//server.c
//
//  UDP 套接字编程呢过典型模型
//
//		客户端							服务器端
//	创建套接字(socket)				创建套接字(socket)
//									绑定服务器地址和端口(bind)
//	客户端发送请求(sendto)	---->	接收客户端请求(recvfrom)
//	客户端接收响应(recvfrom)<----	回送响应(sendto)
//	关闭套接字(close)	
//man 7 socket
//accept() , bind() , connect() ,  getsockname()  ,  getsockopt()  ,
//listen()  , recv() , recvfrom() , recvmsg() , send() , sendmsg() ,
//sendto() , setsockopt() , shutdown() , socket() , socketpair() 
//
//socket - create an endpoint for communication
//#include <sys/socket.h>
//int socket(int domain, int type, int protocol);
//RETURN VALUE
//Upon successful completion, socket() shall return  a  non-negative
//integer,  the  socket  file  descriptor.  Otherwise, a value of -1
//shall be returned and errno set to indicate the error.
//
//bind - bind a name to a socket
//#include <sys/socket.h>
//int bind(int socket, const struct sockaddr *address,
//        socklen_t address_len);
//RETURN VALUE
//Upon  successful  completion, bind() shall return 0; otherwise, -1
//shall be returned and errno set to indicate the error.
//
//listen  -  listen  for  socket  connections  and limit the queue of
//incoming connections
//#include <sys/socket.h>
//int listen(int socket, int backlog);
//RETURN VALUE
//Upon successful completions, listen() shall return 0; otherwise, -1
//shall be returned and errno set to indicate the error.
//
//connect - connect a socket
//#include <sys/socket.h>
//int connect(int socket, const struct sockaddr *address,
//            socklen_t address_len);
//RETURN VALUE
//Upon successful completion, connect() shall return 0; otherwise, -1
//shall be returned and errno set to indicate the error.
//
//accept - accept a new connection on a socket
//#include <sys/socket.h>
//int accept(int socket, struct sockaddr *restrict address,
//          socklen_t *restrict address_len);
//RETURN VALUE
//Upon  successful completion, accept() shall return the non-negative
//file descriptor of the accepted  socket.  Otherwise,  -1  shall  be
//returned and errno set to indicate the error.
//
//send, sendto, sentmsg  - send a message on a socket
//#include <sys/socket.h>
//ssize_t  send(int  socket,  const  void *buffer, size_t length, int
//flags);
//ssize_t sendto(int socket, const void *message, size_t length,
//    int flags, const struct sockaddr *dest_addr,socklen_t dest_len);
//ssize_t  sendmsg(int  socket,  const  struct  msghdr  *message, int
//flags);
//RETURN VALUE
//Upon successful completion, shall return the number of bytes
//sent. Otherwise, -1 shall be returned and errno set to indicate the
//error.
//
//recv, recvfrom, recvmsg - receive a message from a socket
//#include <sys/types.h>
//#include <sys/socket.h>
//ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//
//ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
//                struct sockaddr *src_addr, socklen_t *addrlen);
//
//ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
//RETURN VALUE
//These  calls return the number of bytes received, or -1 if an error
//occurred. The  return value will be 0 when the peer has performed an
//orderly shutdown.
//
//struct iovec {                    /* Scatter/gather array items */
//    void  *iov_base;              /* Starting address */
//    size_t iov_len;               /* Number of bytes to transfer */
//};
//
//struct msghdr {
//    void         *msg_name;       /* optional address */
//    socklen_t     msg_namelen;    /* size of address */
//    struct iovec *msg_iov;        /* scatter/gather array */
//    size_t        msg_iovlen;     /* # elements in msg_iov */
//    void         *msg_control;    /* ancillary data, see below */
//    size_t        msg_controllen; /* ancillary data buffer len */
//    int           msg_flags;      /* flags on received message */
//};
//
//socketpair - create a pair of connected sockets
//#include <sys/socket.h>
//int socketpair(int domain, int type, int protocol,
//                            int socket_vector[2]);
//RETURN VALUE
//Upon  successful  completion,  this function shall return 0; 
//otherwise, -1 shall be returned and errno set to indicate the error.
//
//setsockopt - set the socket options
//#include <sys/socket.h>
//int setsockopt(int socket, int level, int option_name,
//               const void *option_value, socklen_t option_len);
//RETURN VALUE
//Upon successful completion, setsockopt() shall return 0. 
//Otherwise, -1 shall be returned and errno set to indicate the error.
//
//getsockopt - get the socket options
//#include <sys/socket.h>
//int getsockopt(int socket, int level, int option_name,
//    void *restrict option_value, socklen_t *restrict option_len);
//RETURN VALUE
//Upon successful completion, getsockopt() shall return 0; 
//otherwise, -1 shall be returned and errno set to indicate the error.
//
//getsockname - get the socket name
//#include <sys/socket.h>
//int getsockname(int socket, struct sockaddr *restrict address,
//                socklen_t *restrict address_len);
//RETURN VALUE
//Upon successful completion, 0 shall be returned, the address argu‐
//ment shall point to the address of the socket, and the address_len
//argument  shall point to the length of the address.  Otherwise, -1
//shall be returned and errno set to indicate the error.
//
//shutdown - shut down socket send and receive operations
//#include <sys/socket.h>
//int shutdown(int socket, int how);
//how    Specifies the type of shutdown. The values are as follows:
//SHUT_RD		Disables further receive operations.
//SHUT_WR		Disables further send operations.
//SHUT_RDWR		Disables further send and receive operations.
//RETURN VALUE
//Upon  successful completion, shutdown() shall return 0; otherwise,
//-1 shall be returned and errno set to indicate the error.
//
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>

#define PORT	8000
#define BUF_SIZE	1024

int main()
{
	struct sockaddr_in serv_addr, clie_addr;
	int res;
	socklen_t clie_addrlen;
	int sockfd;
	char buf[BUF_SIZE];
	char str[INET_ADDRSTRLEN];

	//建立socket连接
	//int socket(int domain, int type, int protocol);
	//以默认协议,在INET域建立数据报套接字
	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	{
		perror("Error scoket");
		exit(-1);
	}
	printf("套接字 ID = %d", sockfd);

	//设置sockaddr_in结构中的相关参数
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(PORT);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	bzero(&(serv_addr.sin_zero), 8);

	int i = 1;	//允许重复使用本地地址与套接字进行绑定
	//int setsockopt(int socket, int level, int option_name,
	//               const void *option_value, socklen_t option_len);
	if ((setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i))) == -1)
	{
		perror("Error setsockopt");
		exit(-1);
	}

	//绑定端口及服务器地址 bind函数
	//int bind(int socket, const struct sockaddr *address,
	//        socklen_t address_len);
	if((bind(sockfd, (struct sockaddr *)&serv_addr,\
					sizeof(struct sockaddr))) == -1)
	{
		perror("Error bind");
		exit(-1);
	}
	printf("绑定成功!\n");

	while(1)
	{
		clie_addrlen = sizeof(clie_addr);
		memset(buf, 0, sizeof(buf));
		//调用recvfrom 接受客户端请求
		//ssize_t recvfrom(int sockfd, void *buf, size_t len, 
		//int flags, struct sockaddr *src_addr, socklen_t *addrlen);

		if((res = recvfrom(sockfd, buf, sizeof(buf), 0,\
				(struct sockaddr *)&clie_addr, &clie_addrlen)) == -1)
		{
			perror("Error recvfrom");
			exit(-1);
		}
		if((inet_ntop(AF_INET, &clie_addr.sin_addr.s_addr,\
						str, INET_ADDRSTRLEN)) == NULL)
		{
			perror("Error inet_ntop after recvfrom");
			exit(-1);
		}
		printf("接收到来自(%s)的消息:%s(%d个字节)\n", str, buf, res);
		
		//调用 sendto 函数回复一条消息
		
		//ssize_t sendto(int socket, const void *message, 
		//	size_t length,int flags, 
		//	const struct sockaddr *dest_addr,socklen_t dest_len);
		memset(buf, 0, sizeof(buf));
		sprintf(buf, "%s信息已收到!", str);

		if((res = sendto(sockfd, buf, strlen(buf), 0,\
				(struct sockaddr *)&clie_addr, clie_addrlen)) == -1)
		{
			perror("Error send");
			exit(-1);
		}
	}	//end while(1)
	
	close(sockfd);
	exit(0);
}

执行结果

  客户端可以带参也可以缺省,用默认值。
执行结果