无连接的数据传输

 

用于无连接套接字的读写函数情况要复杂一点。由于没有建立一个连接,所以每次发送数据的过程中都要明确指明该数据包的地址,同时,在接收数据包的时候,接受进程能够得到发送该数据包的地址,从而知道该数据包从哪里来。

Linux环境中提供有专门对无连接的套接字进行读写的函数,这两个函数分别为sendto函数和recvfrom函数,函数原型如下:

 int sendto(int sockfd, const *restrict buf, size_t len, int flags, struct sockaddr * restrict destaddr, socket_len *restrict destlen); 

头文件: #include <sys/types.h> #include <sys/socket.h> 

参数说明:

第一个参数sockfd表示通信用的套接字。

第二个参数buf表示发送内容所在的缓冲区。

第三个参数len表示需要发送的字节数。

第四个参数flags是传输标志位,一般设0,详细描述请参考send()。

第五个参数destaddr是一个sockaddr地址结构的地址,该地址表示数据报的目的地,结构sockaddr 请参考bind。

第六个参数destlen表示数据报目的地址结构大小。

返回值:成功返回实际传送出去的字符数,失败返回-1。

 int recvfrom (int sockfd, const *restrict buf, size_t len, int flags, struct sockaddr * restrict addr, socket_len *restrict addrlen); 

头文件: #include <sys/types.h> #include <sys/socket.h> 

参数说明:

第一个参数sockfd表示通信用的套接字。

第二个参数buf表示存储接收数据的缓冲区。

第三个参数len表示需要接收的字节数。

第四个参数flags是传输标志位。

第五个参数addr是一个sockaddr地址结构的地址,该地址表示数据报的发送地址。

第六个参数addrlen表示数据报目的地址结构大小。

无连接的数据传说一般使用的是UDP协议,还是使用大小写字母转换的例子来演示无连接服务的服务器端程序。无连接服务器端执行流程如下:

 

服务器端程序代码如下所示:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <errno.h>
#define MAX_LINE 100

/*处理函数,将大写字符转换成小写字符。参数为需要转换的字符串*/
void my_fun(char *p)
{
       if(p == NULL)
              return ;
       for(; *p != '\0'; p++)
              if(*p >= 'A' && *p <= 'Z')
                     *p = *p - 'A' + 'a';
}

int main(void)
{
       struct sockaddr_in sin;
       struct sockaddr_in cin;
       int s_fd;
       int port = 8000;
       socklen_t addr_len;
       char buf[MAX_LINE];
       char addr_p[INET_ADDRSTRLEN];
       int n;
       /*填写地址结构*/
       bzero(&sin, sizeof(sin));
       sin.sin_family = AF_INET;
       sin.sin_addr.s_addr = INADDR_ANY;
       sin.sin_port = htons(port);
       /*使用UDP通信协议创建一个套接字,并且得到发送本数据包的客户端地址*/
       s_fd = socket(AF_INET, SOCK_DGRAM, 0);
       if(s_fd == -1)
       {
              perror("fail to create socket");
              exit(1);
       }
       /*将套接字绑定到一个地址*/
       if(bind(s_fd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
       {
              perror("call to bind");
              exit(1);
       }

       /*服务器是一个死循环,一次循环处理一个请求*/
       while(1)
       {
              addr_len = sizeof(sin);
              /*UDP协议是无连接的,所以只有一个套接字接受客户端传输的数据报即可
               *而不需要在创建一个套接字,用于建立连接
               *同样的使用UDP协议的网络程序也不需要调用accept函数
              **/
               ///接收客户端传送过来的字符串
              n = recvfrom(s_fd, buf, MAX_LINE, 0, (struct sockaddr *) &cin, &addr_len);
              if(n == -1)
              {
                     perror("fail to receive");
                     exit(1);
              }
              /*将客户端地址转换成字符串*/
              inet_ntop(AF_INET, &cin.sin_addr, addr_p, sizeof(addr_p));
              printf("client IP is %s, port is %d\n", addr_p, ntohs(cin.sin_port));     ///打印客户端地址和端口号
              printf("content is : %s\n", buf);            ///打印客户端发送过来的字符串
              my_fun(buf);
              /*使用sendto函数将转换后的字符串回传给客户端程序*/
              n = sendto(s_fd, buf, n, 0, (struct sockaddr *) &cin, addr_len);
              if(n == -1)
              {
                     perror("fail to send");
                     exit(1);
              }
       }
       if(close(s_fd) == -1)
       {
              perror("fail to close");
              exit(1);
       }
       return 0;
}

客户端程序代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#define MAX_LINE 80

int main(int argc, char *argv[ ])
{
       struct sockaddr_in sin;
       struct sockaddr_in cin;
       int port = 8000;
       socklen_t addr_len;
       int s_fd;
       char *str = "test";
       char buf[MAX_LINE];
       char add_p[INET_ADDRSTRLEN];
       int n;
       if(argc != 2)
       {
              printf("wrong command\n");
              exit(1);
       }
       str = argv[1];
       bzero(&sin, sizeof(sin));
       /*使用IP地址族*/
       sin.sin_family = AF_INET;
       /*与本机的服务器程序通信,使用本机的IP地址*/
       inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr);
       sin.sin_port = htons(port);
       s_fd = socket(AF_INET, SOCK_DGRAM, 0);
       if(s_fd == -1)
       {
              perror("fail to create socket");
              exit(1);
       }
       sprintf(buf, "%s\0", str);
       n = sendto(s_fd, buf, strlen(str) + 1, 0, (struct sockaddr *)&sin, sizeof(sin));
       if(n == -1)
       {
              perror("fail to send\n");
              exit(1);
       }
       addr_len = sizeof(cin);
       n = recvfrom(s_fd, buf, MAX_LINE, 0, (struct sockaddr *) &cin, &addr_len);
       if(n == -1)
       {
              perror("fail to receive");
              exit(1);
       }
       else
              printf("receive from server : %s\n", buf);
       if(close(s_fd) == -1)
       {
              perror("fail to close");
              exit(1);
       }
       return 0;
}

 

posted @ 2017-04-23 22:22  杨静远  阅读(645)  评论(0编辑  收藏  举报