UDP编程
对于UDP编程,我们首先需要掌握的是下图中的内容,对于编程时服务器和客户端分别需要实现的功能.
它是一种面向无连接的传输协议,何为面向无连接,就是在传输数据的时候,不需要判断是否与服务端建立连接就可发送数据,对方是否成功接收并不知情。这样就导致在传输的时候安全性较差,无法保证数据准确抵达,但在传输数据的效率上会稍微快一点。
头文件
以下是本次编程过程中需要用到的头文件以及宏定义
net.h
#ifndef _NET_H
#define _NET_H
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<errno.h>
#include<pthread.h>
#include <ifaddrs.h>
#endif
common.h
#ifndef _COMMON_H
#define _COMMON_H
#define SERV_PORT 5001
#define SERV_IP_ADDR "127.0.0.1"//本地回环地址
#define BACKLOG 5//请求队列大小
#define QUIT_STR "quit"
#endif
实现一个简单的UDP编程
客户端(client.c)
/*./client serv_ip serv_port*/
#include"net.h"
#include"common.h"
int main(int argc,char **argv){
int fd = -1;
int port = SERV_PORT;
struct sockaddr_in sin;
//输入参数判断
if(argc != 3){
printf("请输入: %s <serverip> <port>\n",argv[0]);
}
/*创建socket fd*/
if((fd = socket(AF_INET,SOCK_DGRAM,0))<0){
perror("socket");
exit(-1);
}
if(atoi(argv[2]) < 5000 || atoi(argv[2]) > 65535){
printf("不正确的端口号%d,用缺省端口号5001\n",port);
}else{
port = atoi(argv[2]);
}
/*连接服务器*/
/*填充struct sockaddr_in结构体变量*/
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
if(inet_pton(AF_INET,argv[1],(void *)&sin.sin_addr)!= 1){
perror("inet_pton");
exit(-1);
}
/*读写数据*/
char buf[BUFSIZ];
while(1){
bzero(buf,BUFSIZ);
printf("请输入 > ");
if(fgets(buf,BUFSIZ-1,stdin) == NULL){
perror("fgets");
continue;
}
sendto(fd,buf,strlen(buf),0,(struct sockaddr *)&sin,sizeof(sin));
if(!strncasecmp(buf,QUIT_STR,strlen(QUIT_STR))){
printf("客户端退出!\n");
break;
}
}
/*关闭套接字*/
close(fd);
return 0;
}
服务器(server.c)
#include"net.h"
#include"common.h"
int main(void){
int fd = -1;
int port = SERV_PORT;
int i;
struct sockaddr_in sin;
struct ifaddrs * ifAddrStruct=NULL;
void * tmpAddrPtr=NULL;
//查询本机网卡对应IP地址
getifaddrs(&ifAddrStruct);
puts("请选择以下网卡对应IP地址进行连接服务器:");
while (ifAddrStruct!=NULL) {
if (ifAddrStruct->ifa_addr->sa_family==AF_INET) {
// check it is IP4
// is a valid IP4 Address
tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
char addressBuffer[INET_ADDRSTRLEN];
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
printf("网卡:%-5s IPV4 地址:%s\n", ifAddrStruct->ifa_name, addressBuffer);
}
/*
else if (ifAddrStruct->ifa_addr->sa_family==AF_INET6) {
// check it is IP6
// is a valid IP6 Address
tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
char addressBuffer[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
printf("网卡:%-5s IPV6 地址:%s\n", ifAddrStruct->ifa_name, addressBuffer);
}
*/
ifAddrStruct=ifAddrStruct->ifa_next;
}
//先输入服务器程序的端口号
printf("请输入端口号( >5000 ):");
scanf("%d", &i);
if(i < 5000 || i > 65535)
printf("不正确的端口号%d,用缺省端口号5001\n",i);
else
port = i;
/*创建socket fd*/
if((fd = socket(AF_INET,SOCK_DGRAM,0))<0){
perror("socket");
exit(-1);
}
/*允许绑定地址快速重用*/
int b_reuse = 1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&b_reuse,sizeof(int));
/*填充struct sockaddr_in结构体变量*/
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = htonl(INADDR_ANY);
/*绑定*/
if(bind(fd,(struct sockaddr *)&sin,sizeof(sin))<0){
perror("bind");
exit(-1);
}
puts("等待连接....");
char buf[BUFSIZ];
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
while(1){
bzero(buf,BUFSIZ);
if(recvfrom(fd,buf,BUFSIZ-1,0,(struct sockaddr *)&cin,&addrlen) < 0){
perror("recvfrom");
continue;
}
char ipv4_addr[16];
if(!inet_ntop(AF_INET,(void *)&cin.sin_addr,ipv4_addr,sizeof(cin))){
perror("inet_ntop");
exit(-1);
}
printf("客户端(%s:%d)输出 > :%s",ipv4_addr,ntohs(cin.sin_port),buf);
if(!strncasecmp(buf,QUIT_STR,strlen(QUIT_STR))){
printf("客户端(%s:%d)号退出!\n",ipv4_addr,ntohs(cin.sin_port));
}
}
close(fd);
return 0;
}