您的位置:首页 > 理论基础 > 计算机网络

UNIX网络编程笔记 第八章 基本UDP套接字编程

2016-09-16 12:55 211 查看
recvfrom和sendto函数:

#include <sys/socket.h>

ssize_t recvfrom(int sockfd,void *buf,size_t nbytes,int flags,struct sockaddr *from,socklen_t *addrlen);

ssize_t sendto(int sockfd,void *buf,size_t nbytes,int flags,struct sockaddr *to,socklen_t addrlen);

//若成功则返回读或写的字节数,若出错返回-1

//tcp套接字read时返回0代表连接已关闭;udp套接字则不然,recvfrom返回0是一种正常状态


udp的异步错误:

如果udp客户端向一个服务进程未启动的服务端发送数据,虽然网络会返回一个端口不可达错误,但是客户端进程的sendto并不会返回错误,而是返回成功(因为udp输出操作成功返回,仅仅代表在接口输出队列中具有存放该IP数据报的空间,但是ICMP错误要更晚一些时候才返回,这就是称其为异步的原因)。

一个几本原则是:对于一个udp套接字,由它引发的异步错误并不返回给它,除非它已连接(调用connect函数)

示例代码:
:

//server.c
#include "common.h"
#include <poll.h>
#include <limits.h>

int main(int argc, char **agrv){

int tcpsockfd,udpsockfd,tcpclientfd;
struct sockaddr_in serveraddr,clientaddr;
socklen_t addrlen = sizeof(clientaddr);

bzero(&serveraddr,sizeof(serveraddr));
bzero(&clientaddr,sizeof(clientaddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(45000);
inet_pton(AF_INET,"127.0.0.1",&serveraddr.sin_addr.s_addr);

tcpsockfd = socket(AF_INET,SOCK_STREAM,0);
bind(tcpsockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
listen(tcpsockfd,20);

serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(45000);
inet_pton(AF_INET,"127.0.0.1",&serveraddr.sin_addr.s_addr);

udpsockfd = socket(AF_INET,SOCK_DGRAM,0);
bind(udpsockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));

struct pollfd allsockets[OPEN_MAX];
for(int i = 0; i < OPEN_MAX; i ++){
allsockets[i].fd = -1;
}

allsockets[0].fd = tcpsockfd;
allsockets[0].events = POLLRDNORM;

allsockets[1].fd = udpsockfd;
allsockets[1].events = POLLRDNORM;

int maxi = 1;
int i;
char buf[800];

while(1){

int newMaxi = 0;
for(int i = 0; i <= maxi; i++){
if(allsockets[i].fd != -1)
newMaxi = i;
}
maxi = newMaxi;

int nready = poll(allsockets,maxi+1,-1);

if(allsockets[0].revents & (POLLRDNORM | POLLERR)){
tcpclientfd = accept(tcpsockfd,(struct sockaddr*)&clientaddr,&addrlen);
if(tcpclientfd < 0){
if(errno == EINTR){
;
}else{
puts("accept error");
}
}else{
for(i = 2; i < OPEN_MAX; i++){
if(allsockets[i].fd == -1){
allsockets[i].fd = tcpclientfd;
allsockets[i].events = POLLRDNORM;
maxi = MAX(maxi,i);
break;
}
}
}
nready--;
}

if(allsockets[1].revents & POLLRDNORM){
int readnum = recvfrom(udpsockfd,buf,sizeof(buf),0,(struct sockaddr*)&clientaddr,&addrlen);
printf("read %d bytes from udp client\n",readnum);
if(readnum < 0){
close(udpsockfd);
puts("read from udpclient error");
}else{
buf[readnum] = 0;
printf("%s",buf);
int sendnum = sendto(udpsockfd,buf,strlen(buf),0,(struct sockaddr*)&clientaddr,addrlen);
if(sendnum < 0) err_sys("udp send error");
else
printf("%d bytes sent\n",readnum);
}

nready--;
}

for(i = 2; i <= maxi; i++){
int tcpclientfd = allsockets[i].fd;
if(tcpclientfd != -1 && (allsockets[i].revents & POLLRDNORM)){
int readnum = read(tcpclientfd,buf,sizeof(buf));
buf[readnum] = 0;
if(readnum < 0){
if(errno == EINTR){
continue;
}else{
close(tcpclientfd);
allsockets[i].fd = -1;
puts("rad error");
}
}else if (readnum == 0){
close(tcpclientfd);
allsockets[i].fd = -1;
puts("tcp client close socket");
}else{
printf("%s",buf);
int writenum = write(tcpclientfd,buf,readnum);
if(writenum < 0){
err_sys("write error");
}else{
printf("%d bytes sent\n",readnum);
}
}
if(--nready <= 0)
break;
}
}

}

}


//client.c
#include "common.h"

int main(int argc, char **argv){

int sockfd;
struct sockaddr_in serveraddr,clientaddr;
char buf[100];

bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
inet_pton(AF_INET,"127.0.0.1",&serveraddr.sin_addr.s_addr);
serveraddr.sin_port = htons(45000);

bzero(&clientaddr,sizeof(clientaddr));

sockfd = socket(AF_INET,SOCK_DGRAM,0);

int rtn = connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
if(rtn != 0){
err_sys("connect error");

}

fd_set readset;
FD_ZERO(&readset);
FD_SET(sockfd,&readset);
int sockStdin = fileno(stdin);
FD_SET(fileno(stdin),&readset);

int stdineof = 0;

while (1) {
FD_SET(sockfd,&readset);
int maxfd = sockfd;
if(stdineof == 0) {
FD_SET(sockStdin,&readset);
maxfd = MAX(sockfd,fileno(stdin));
}
int nReady = select(maxfd + 1,&readset,NULL,NULL,NULL);
printf("nReady = %d\n",nReady);
socklen_t addrlen = sizeof(clientaddr);
if(nReady > 0){
if(FD_ISSET(sockStdin,&readset)){
puts("read from stdin");
int readNum = read(sockStdin,buf,sizeof(buf));
if(readNum == 0){
puts("eof, close socket");
shutdown(sockfd,1);
FD_CLR(sockStdin,&readset);
stdineof = 1;
continue;

}
//int sendnum = sendto(sockfd,buf,readNum,0,(struct sockaddr*)&serveraddr,addrlen);
int sendnum = write(sockfd,buf,readNum);
if(sendnum < 0) err_sys("sendto error");
printf("%d bytes sent\n",sendnum);
}

if(FD_ISSET(sockfd,&readset)){
puts("read from server");
//int readNum = recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&serveraddr,&addrlen);
int readNum = read(sockfd,buf,sizeof(buf));
if(readNum == 0){
if(stdineof == 1) {
puts("server close socket");
return 0;
}
else err_sys("client read error");
}
write(fileno(stdout),buf,readNum);

}

}

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络编程