UDP:用户数据报协议,它不提供可靠传输,只负责数据传输,是无连接的
服务器端:
因udp是无连接的,因此不用将套接字设为监听状态
1.创建套接字使用socket(int domain,int type,int protocol)函数
2.将套接字信息填充到内核,进行绑定
3.利用recvfrom()函数与客户端进行数据通信
recvfrom函数原型:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
从(已连接)套接口上接收数据,并获取数据发送方的地址。
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<sys/types.h> 5 #include<arpa/inet.h> 6 #include<netinet/in.h> 7 #include<sys/socket.h> 8 9 void Usage(char *proc) 10 { 11 printf("Usage:%s [ip] [port]\n",proc); 12 } 13 int main(int argc,char* argv[]) 14 { 15 if(argc!=3) 16 { 17 Usage(argv[0]); 18 exit(1); 19 } 20 21 int sock=socket(AF_INET,SOCK_DGRAM,0); 22 if(sock < 0) 23 { 24 perror("socket"); 25 exit(2); 26 } 27 int _port=atoi(argv[2]); 28 char* _ip=argv[1]; 29 struct sockaddr_in client; 30 client.sin_family=AF_INET; 31 client.sin_port=htons(_port); 32 client.sin_addr.s_addr=inet_addr(_ip); 33 socklen_t len=sizeof(client); 34 if((bind(sock,(struct sockaddr*)&client,len))<0) 35 { 36 perror("bind"); 37 return -1; 38 } 39 int done=0; 40 char buf[1024]; 41 while(!done) 42 { 43 memset(buf,‘\0‘,sizeof(buf));
44 ssize_t _size=recvfrom(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&c lient,&len);
45 if(_size>0)
46 {
47 buf[_size]=‘\0‘;
48 printf("[[ip:%s] [port:%d]]:client#%s",inet_ntoa(client.sin_addr ),ntohs(client.sin_port),buf);
49 }else if(_size==0)
50 {
51 printf("client quit...\n");
52 exit(2);
53 }else
54 {
55 perror("recvfrom");
56 return 1;
57 }
58 }
59
60 return 0;
61 }
客户端:
使用sendto()函数,发送数据进行传输
sendto()函数原型:
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<sys/types.h> 5 #include<arpa/inet.h> 6 #include<netinet/in.h> 7 #include<sys/socket.h> 8 9 void Usage(char *proc) 10 { 11 printf("Usage:%s [remoteip] [remoteport]\n",proc); 12 } 13 int main(int argc,char* argv[]) 14 { 15 if(argc!=3) 16 { 17 Usage(argv[0]); 18 exit(1); 19 } 20 int sock=socket(AF_INET,SOCK_DGRAM,0); 21 if(sock < 0) 22 { 23 perror("socket");
24 exit(1);
25 }
26 int _port=atoi(argv[2]);
27 char* _ip=argv[1];
28 struct sockaddr_in remote;
29 remote.sin_family=AF_INET;
30 remote.sin_port=htons(_port);
31 remote.sin_addr.s_addr=inet_addr(_ip);
32 socklen_t len=sizeof(remote);
33 int done=0;
34 char buf[1024];
35 while(!done)
36 {
37 memset(buf,‘\0‘,sizeof(buf));
38 printf("please input:");
39 fflush(stdout);
40 ssize_t _size=read(0,buf,sizeof(buf)-1);
41 if(_size < 0)
42 {
43 perror("read");
44 return 2;
45 }
46 sendto(sock,buf,sizeof(buf)-1,0,(struct sockaddr*)&remote,len);
47 }
48 return 0;
49 }
运行结果:
端口号分配:(端口号即进程标识符)
TCP/IP的运输层使用一个16位的端口号来标识一个端口,端口号只具有本地意义,只是为了标志本计算机应用层的各个进程在和运输层交互时的层间接口,在因特网的不同计算机,相同的端口号是没有关联的。
服务器一般都是通过知名端口号来识别的。例如,对于TCP/IP实现来说,每个FTP服务器的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(普通文件传输协议)服务器的UDP端口号都是69。
1).服务器端使用的端口号:
(1):熟知端口号为0~1023,IANA把这些端口号指派给了TCP/IP最重要的应用程序,让所有用户都可以知道。
(2).登记端口号:为1024~49151,是为没有熟知端口号的应用程序使用的,使用这类端口号必须在IANA按照规定登记,以防重复。
2).客户端使用的端口号:49152~65535,因此类端口号仅在客户进程进行时才动态选择,可称之为短暂端口号,当服务器进程收到客户进程的报文时,就知道了客户进程使用的端口号,因此可将数据发送给客户进程,通信结束该客户端口号不存在,可以提供给其他客户进程使用。
Internet扩展服务与UNIX特定服务之间的一个差别就是telnet和rlogin,它们二者都允许通过计算机网络登录到其他主机上。telnet是采用端口号为23的TCP/IP标准,且几乎可以在所有操作系统上进行实现。相反,rlogin最开始时只是为UNIX系统设计的(尽管许多非UNIX系统现在也提供该服务)。客户端口号又称做临时端口号(即存在时间很短暂),这是因为它通常只是在用户运行该客户程序时才存在,而服务器则只要主机开着,其服务就运行。
大多数TCP/IP实现给临时端口分配1 024~5 000之间的端口号。大于5 000的端口号是为其他服务器预留的(Internet上并不常用的服务)。大多数Linux系统的文件/etc/services都包含了人们熟知的端口号。