第八章 基本UDP套接字编程:
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void * buff, size_t nbytes, int flags,
struct sockaddr * from, socklen_t * addrlen);
success return read-bytes(0 means recv a empty package), error return -1
so it is different from tcp-read/recv(0 means get FIN)
since it can use by tcp socket
ssize_t sendto(int sockfd, const void * buff, size_t nbytes, in flags,
const struct sockaddr * to, socklen_t addrlen);
success return write-bytes, error return -1
we can send a empty package(0 bytes)
it can use by tcp socket
示例:
#ifndef __ERROR_EXIT_H__
#define __ERROR_EXIT_H__
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
void err_exit(const char * msg)
{
printf("%s: %s\n", msg, strerror(errno));
exit(1);
}
#endif
#include <netinet/in.h>
#include <sys/socket.h>
#include "dg_echo.h"
#include "err_exit.h"
#define SERV_PORT 34567
int
main(int argc, char * argv[])
{
int sockfd;
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
err_exit("socket error");
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
if (bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
err_exit("bind error");
}
dg_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
}
#include <netinet/in.h>
#include <sys/socket.h>
#include "err_exit.h"
#define MAXLINE 4096
void
dg_echo(int sockfd, struct sockaddr * pcliaddr, socklen_t clilen)
{
int n;
socklen_t len;
char mesg[MAXLINE];
for ( ; ; ) {
len = clilen;
if ((n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len)) == -1) {
err_exit("recvfrom error");
}
if (sendto(sockfd, mesg, n, 0, pcliaddr, len) == -1) {
err_exit("sendto error");
}
}
}
#include <netinet/in.h>
#include <sys/socket.h>
#include "dg_cli.h"
#include "err_exit.h"
#define SERV_PORT 34567
int
main(int argc, char * argv[])
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2) {
printf("usage: udpcli <IPaddress>\n");
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {
err_exit("inet_pton error");
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
err_exit("socket error");
}
dg_cli(stdin, sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
exit(0);
}
#include <netinet/in.h>
#include <sys/socket.h>
#include "err_exit.h"
#define MAXLINE 4096
void
dg_cli(FILE * fp, int sockfd, const struct sockaddr * pservaddr,
socklen_t servlen)
{
int n;
char sendline[MAXLINE];
char recvline[MAXLINE + 1];
while (fgets(sendline, MAXLINE, fp) != NULL) {
if (sendto(sockfd, sendline, strlen(sendline),
0, pservaddr, servlen) == -1) {
err_exit("sendto error");
}
if ((n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) == -1) {
err_exit("recvfrom error");
}
recvline[n] = 0; /* null terminate */
if (fputs(recvline, stdout) == EOF) {
err_exit("fputs error");
}
}
}
#include <netinet/in.h>
#include <sys/socket.h>
#include "err_exit.h"
#include "sock_ntop.h"
#define MAXLINE 4096
void
dg_cli(FILE * fp, int sockfd, const struct sockaddr * pservaddr,
socklen_t servlen)
{
int n;
char sendline[MAXLINE];
char recvline[MAXLINE + 1];
char * paddr;
socklen_t len;
struct sockaddr * preply_addr;
if ((preply_addr = malloc(servlen)) == NULL) {
err_exit("malloc error");
}
while (fgets(sendline, MAXLINE, fp) != NULL) {
if (sendto(sockfd, sendline, strlen(sendline),
0, pservaddr, servlen) == -1) {
err_exit("sendto error");
}
len = servlen;
if ((n = recvfrom(sockfd, recvline, MAXLINE,
0, preply_addr, &len)) == -1) {
err_exit("recvfrom error");
}
/*
* it is not a good idea to use "memcmp"
* cause may sendto-remote-ip and recvfrom-remote-ip is different
* but they are in a same machine
* so we may drop a right response
*/
if (len != servlen || memcmp(pservaddr, preply_addr, len) != 0) {
if ((paddr = sock_ntop(preply_addr, len)) == NULL) {
err_exit("sock_ntop error");
}
printf("reply from %s (ignored)\n", paddr);
continue;
}
recvline[n] = 0; /* null terminate */
if (fputs(recvline, stdout) == EOF) {
err_exit("fputs error");
}
}
}
#include <netinet/in.h>
#include <sys/socket.h>
#include "err_exit.h"
#define MAXLINE 4096
void
dg_cli(FILE * fp, int sockfd, const struct sockaddr * pservaddr,
socklen_t servlen)
{
int n;
char sendline[MAXLINE];
char recvline[MAXLINE + 1];
if (connect(sockfd, (struct sockaddr *)pservaddr, servlen) == -1) {
err_exit("connect error");
}
while (fgets(sendline, MAXLINE, fp) != NULL) {
if (write(sockfd, sendline, strlen(sendline)) == -1) {
err_exit("write error");
}
if ((n = read(sockfd, recvline, MAXLINE)) == -1) {
err_exit("read error");
}
recvline[n] = 0; /* null terminate */
if (fputs(recvline, stdout) == EOF) {
err_exit("fputs error");
}
}
}
#include <netinet/in.h>
#include <sys/socket.h>
#include "err_exit.h"
#define NDG 2000 /* datagrams to send */
#define DGLEN 1400 /* length of each datagram */
void
dg_cli(FILE * fp, int sockfd, const struct sockaddr * pservaddr,
socklen_t servlen)
{
int i;
char sendline[DGLEN];
for (i = 0; i < NDG; i++) {
if (sendto(sockfd, sendline, DGLEN, 0, pservaddr, servlen) == -1) {
err_exit("sendto error");
}
}
}
#include <netinet/in.h>
#include <sys/socket.h>
#include "err_exit.h"
#include "my_signal.h"
#define MAXLINE 4096
int count;
void
recvfrom_int(int signo)
{
printf("\nreceived %d datagrams\n", count);
exit(0);
}
void
dg_echo(int sockfd, struct sockaddr * pcliaddr, socklen_t clilen)
{
socklen_t len;
char mesg[MAXLINE];
if (my_signal(SIGINT, recvfrom_int) == SIG_ERR) {
err_exit("my_signal error");
}
for ( ; ; ) {
len = clilen;
if (recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len) == -1) {
err_exit("recvfrom error");
}
count++;
}
}
#include <netinet/in.h>
#include <sys/socket.h>
#include "err_exit.h"
#include "my_signal.h"
#define MAXLINE 4096
int count;
void
recvfrom_int(int signo)
{
printf("\nreceived %d datagrams\n", count);
exit(0);
}
void
dg_echo(int sockfd, struct sockaddr * pcliaddr, socklen_t clilen)
{
int n;
socklen_t len;
char mesg[MAXLINE];
if (my_signal(SIGINT, recvfrom_int) == SIG_ERR) {
err_exit("my_signal error");
}
n = 220 * 1024;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1) {
err_exit("setsockopt error");
}
for ( ; ; ) {
len = clilen;
if (recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len) == -1) {
err_exit("recvfrom error");
}
count++;
}
}
#include <netinet/in.h>
#include <sys/socket.h>
#include "err_exit.h"
#include "sock_ntop.h"
#define SERV_PORT 34567
int
main(int argc, char * argv[])
{
int sockfd;
char * paddr;
socklen_t len;
struct sockaddr_in cliaddr;
struct sockaddr_in servaddr;
if (argc != 2) {
printf("usage: udpcli <IPaddress>\n");
exit(0);
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
err_exit("socket error");
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {
err_exit("inet_pton error");
}
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
err_exit("connect error");
}
len = sizeof(cliaddr);
if (getsockname(sockfd, (struct sockaddr *)&cliaddr, &len) == -1) {
err_exit("getsockname error");
}
if ((paddr = sock_ntop((struct sockaddr *)&cliaddr, len)) == NULL) {
err_exit("sock_ntop error");
}
printf("local address %s\n", paddr);
exit(0);
}
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/wait.h>
#include "str_echo.h"
#include "err_exit.h"
#include "my_signal.h"
#define LISTENQ 1024
#define SERV_PORT 34567
#define max(a, b) ((a) >= (b) ? (a) : (b))
void
sig_chld(int signo)
{
pid_t pid;
int stat;
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) { /* waitpid + WNOHANG */
printf("child %d terminated\n", pid);
}
return;
}
int
main(int argc, char * argv[])
{
int listenfd;
int connfd;
int udpfd;
int nready;
int maxfdp1;
char mesg[MAXLINE];
pid_t childpid;
fd_set rset;
ssize_t n;
socklen_t len;
const int on = 1;
struct sockaddr_in cliaddr;
struct sockaddr_in servaddr;
/* create listening TCP socket */
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
err_exit("socket SOCK_STREAM error");
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
err_exit("setsockopt error");
}
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
err_exit("bind error");
}
if (listen(listenfd, LISTENQ) == -1) {
err_exit("listen error");
}
/* create UDP socket */
if ((udpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
err_exit("socket SOCK_DGRAM error");
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
if (bind(udpfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
err_exit("bind error");
}
if (my_signal(SIGCHLD, sig_chld) == SIG_ERR) { /* must call waitpid() */
err_exit("my_signal error");
}
FD_ZERO(&rset);
maxfdp1 = max(listenfd, udpfd) + 1;
for ( ; ; ) {
FD_SET(listenfd, &rset);
FD_SET(udpfd, &rset);
if ((nready = select(maxfdp1, &rset, NULL, NULL, NULL)) == -1) {
if (errno == EINTR) {
continue; /* back to for() */
}
else {
err_exit("select error");
}
}
if (FD_ISSET(listenfd, &rset)) {
len = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len);
if (connfd == -1) {
err_exit("accept error");
}
if ((childpid = fork()) < 0) {
err_exit("fork error");
}
else if (childpid == 0) {
if (close(listenfd) == -1) {
err_exit("close listenfd error");
}
str_echo(connfd); /* process the request */
exit(0);
}
if (close(connfd) == -1) {
err_exit("close connfd error");
}
}
if (FD_ISSET(udpfd, &rset)) {
len = sizeof(cliaddr);
if ((n = recvfrom(udpfd, mesg, MAXLINE, 0,
(struct sockaddr *)&cliaddr, &len)) == -1) {
err_exit("recvfrom error");
}
if (sendto(udpfd, mesg, n, 0,
(struct sockaddr *)&cliaddr, len) == -1) {
err_exit("sendto error");
}
}
}
}