電腦店訊
1 兩個常用的函數
int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr * from int *fromlen)
int sendto(int sockfd,const void *msg,int len,unsigned int flags,struct sockaddr *to int tolen)
sockfd,buf,len的意義和read,write一樣,分別表示套接字描述符,發送或接收的緩沖區及大小.
recvfrom負責從sockfd接收數據,如果from不是NULL,那麼在from裡面存儲了信息來源的情況,如果對信息的來源不感興趣,可以將from和fromlen 設置為NULL.sendto負責向to發送信息.此時在to裡面存儲了收信息方的詳細資料.
2 一個實例
CODE:
/* 服務端程序 server.c */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#define SERVER_PORT 8888
#define MAX_MSG_SIZE 1024
void udps_respon(int sockfd)
{
struct sockaddr_in addr;
int n;
socklen_t addrlen;
char msg[MAX_MSG_SIZE];
while(1)
{ /* 從網絡上讀,寫到網絡上面去 */
memset(msg, 0, sizeof(msg));
addrlen = sizeof(struct sockaddr);
n=recvfrom(sockfd,msg,MAX_MSG_SIZE,0,
(struct sockaddr*)&addr,&addrlen);
/* 顯示服務端已經收到了信息 */
fprintf(stdout,"I have received %s",msg);
sendto(sockfd,msg,n,0,(struct sockaddr*)&addr,addrlen);
}
}
int main(void)
{
int sockfd;
struct sockaddr_in addr;
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd<0)
{
fprintf(stderr,"Socket Error:%s\n",strerror(errno));
exit(1);
}
bzero(&addr,sizeof(struct sockaddr_in));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port=htons(SERVER_PORT);
if(bind(sockfd,(struct sockaddr *)&addr,sizeof(struct sockaddr_in))<0)
{
fprintf(stderr,"Bind Error:%s\n",strerror(errno));
exit(1);
}
udps_respon(sockfd);
close(sockfd);
}
客戶端程序
CODE:
/* 客戶端程序 */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#define MAX_BUF_SIZE 1024
void udpc_requ(int sockfd,const struct sockaddr_in *addr,socklen_t len)
{
char buffer[MAX_BUF_SIZE];
int n;
while(fgets(buffer,MAX_BUF_SIZE,stdin))
{ /* 從鍵盤讀入,寫到服務端 */
sendto(sockfd,buffer,strlen(buffer),0,addr,len);
bzero(buffer,MAX_BUF_SIZE);
/* 從網絡上讀,寫到屏幕上 */
memset(buffer, 0, sizeof(buffer));
n=recvfrom(sockfd,buffer,MAX_BUF_SIZE, 0, NULL, NULL);
if(n <= 0)
{
fprintf(stderr, "Recv Error %s\n", strerror(errno));
return;
}
buffer[n]=0;
fprintf(stderr, "get %s", buffer);
}
}
int main(int argc,char **argv)
{
int sockfd,port;
struct sockaddr_in addr;
if(argc!=3)
{
fprintf(stderr,"Usage:%s server_ip server_port\n",argv[0]);
exit(1);
}
if((port=atoi(argv[2]))<0)
{
fprintf(stderr,"Usage:%s server_ip server_port\n",argv[0]);
exit(1);
}
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd<0)
{
fprintf(stderr,"Socket Error:%s\n",strerror(errno));
exit(1);
}
/* 填充服務端的資料 */
bzero(&addr,sizeof(struct sockaddr_in));
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
if(inet_aton(argv[1],&addr.sin_addr)<0)
{
fprintf(stderr,"Ip error:%s\n",strerror(errno));
exit(1);
}
if(connect(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1)
{
fprintf(stderr, "connect error %s\n", strerror(errno));
exit(1);
}
udpc_requ(sockfd,&addr,sizeof(struct sockaddr_in));
close(sockfd);
}
########### 編譯文件Makefile ##########
all:server client
server:server.c
gcc -o server server.c
client:client.c
gcc -o client client.c
clean:
rm -f server
rm -f client
rm -f core
運行UDP Server程序
執行./server &命令來啟動服務程序。我們可以使用netstat -ln命令來觀察服務程序綁定的IP地址和端口,部分輸出信息如下:
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:32768 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:6000 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN
udp 0 0 0.0.0.0:32768 0.0.0.0:*
udp 0 0 0.0.0.0:8888 0.0.0.0:*
udp 0 0 0.0.0.0:111 0.0.0.0:*
udp 0 0 0.0.0.0:882 0.0.0.0:*
可以看到udp處有“0.0.0.0:8888”的內容,說明服務程序已經正常運行,可以接收主機上任何IP地址且端口為8888的數據。
3、運行UDP Client程序
執行./client 127.0.0.1 8888命令來啟動客戶程序,使用127.0.0.1來連接服務程序,執行效果如下:
Hello, World!
Hello, World!
this is a test
this is a test
^d
輸入的數據都正確從服務程序返回了,按ctrl+d可以結束輸入,退出程序。