03 programming ingles - uc3mppacyna/larc/lecture/slides/03_programming_ingles… · lab. comm. netw...
TRANSCRIPT
Laboratory for Architecture of Laboratory for Architecture of Communication Networks: Communication Networks: Chapter 3Chapter 3
Programming GuideProgramming Guide
Spanish lecturers: Spanish lecturers: David David LarrabeitiLarrabeiti LLóópezpezAlberto Alberto GarcGarc ííaa MartMart ííneznez
English lecturer: English lecturer: Piotr PacynaPiotr Pacyna
Lab. Comm. Netw Arch. programming advices 2
Programme authors and contributors
� Programme authors
� Alberto García Martínez� David Larrabeiti López
� Lecturers (english track):� Jorg Diederich� Huw Oliver
� Piotr Pacyna
Lab. Comm. Netw Arch. programming advices 3
Contact
� Teacher: Piotr Pacyna
� Visiting professor at UC3M� Email: [email protected]� Office: 4.1 A16� Phone: +34 91 624 84 59
Lab. Comm. Netw Arch. programming advices 4
Scope of this lecture
1. Software developementand software engineering
2. Controlling and useof the the sound card
3. Event-based processing4. Time-related functions5. Memory management6. Buffer management7. Networking8. Enhancements
Lab. Comm. Netw Arch. programming advices 5
Part I. Software developement
and software engineering
Lab. Comm. Netw Arch. programming advices 6
Some Advice on Programming in C and Unix
� Compiling ... and the program does nothing. What to do?
1. Compile with –g and use a debugger ( gdb - man gdb ).
� Step by step, breakpoints...
2. Manual tracing: on entry / exit buffered
� printf (); fflush (stdout);
� Always check the result of a function call� If unexpected result, print error message� #define LLAMA(v,m) {if ( (v)==-1) {perror
(m); printf (“Error code: %d, %s\n", errno, strerror (errno)); exit (-1); }};
Lab. Comm. Netw Arch. programming advices 7
More Advice on Programming in C and Unix
� Possible reasons for “Segmentation Fault”� ~ 60% of the cases: int *a; (*a) = 3 ;
� ~ 10% of the cases:
� int a[N]; for (i=0 ; i <= N ; i++); a[i]
� ~ 3% of the cases: printf (...) with a wrong number of arguments or type of arguments ���� use gcc with option ‘ -Wall ’ and watch output of gcc carefully (especially the warnings!)
� ~ 1% of the cases: ´ \0 ´ missing at the end of a string
Lab. Comm. Netw Arch. programming advices 8
Debugging
� Write a small piece of code, compile and verify� Repeat this cycle several times
� When writing all code in one block:
� Difficult to know where the program fails
� Sometimes the purpose of the code no longer known
�Comments very useful, but rare in reality…
� Possible failure when debugging programs with several processes:� Remaining processes from the previous run
� killall processName
� pstree -p | grep processName
Lab. Comm. Netw Arch. programming advices 9
Debugging: strace
� Allows to view the sequence of operating system calls� Including the parameters, if they succeeded or not an d
an indication why they did not succeed� For example, useful to debug recvfrom, sendto , ...
� -o file ���� send the information to the file “ file ”
� For multiple processes:� -f prints the process id of the calling process in the fi rst
column
� Moreover: print the time of the calls,…� Useful to debug a real-time application
Lab. Comm. Netw Arch. programming advices 10
Example of strace output
doc010:~/larc> strace ./audio server 4000
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0old_mmap(NULL, 4096, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4001d000write(1, "\n", 1) = 1write(1, "Version 2.0. Demonstration of program"..., 45Version 2.0.
Demonstration of audio program) = 45write(1, "\n", 1) = 1rt_sigaction(SIGINT, {0x8048d10, [INT],
SA_RESTORER|SA_RESTART, 0x400806f8}, {SIG_DFL}, 8) = 0socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3bind(3, {sa_family=AF_INET, sin_port=htons(4000),
sin_addr=inet_addr("0.0.0.0")}, 16) = 0listen(3, 1) = 0accept(3,
Instals SIGINT handler
Socket TCP opened
Port 4000, waits in any address
Listen executedAccept with descriptor #3;the process is blocked waiting
Lab. Comm. Netw Arch. programming advices 11
Debugging: gdb
� Compile your executable with –g� In emacs: ALT-X gdb
� > gdb <ExecutableName>
� break <function> (e.g., break main )
� run <parameters> (e.g., run server 10000 )
� step – step-by-step execution including functions
� next – step-by-step execution without stepping into functions
� print – print a variable value
� Similar syntax as in C
� Multiple processes: Associate with a running process
� gdb <ExecutableName> <ProcessID>
Lab. Comm. Netw Arch. programming advices 12
Debugging
� Be careful with other applications that use the soundcard� Identify the application
� Use strace to see the instruction in which our
code is blocked
� If it is a file, identify the program that is using that
file with�lsof fileName
� Kill the application
Lab. Comm. Netw Arch. programming advices 13
Optimizations
� My program consumes CPU or memory?! � CPU
� Usage of a profiler, e.g. gprof
�Compile with –pg
• Longer execution time
�Analyze the number of function calls and the distribution of the cpu time for the different calls
�Optimize the appropriate functions
� Memory
� Use a memory debugger� malloc
Lab. Comm. Netw Arch. programming advices 14
Part II. Controlling and useof the the sound card
Lab. Comm. Netw Arch. programming advices 15
Sound Card
Output MixerInput Mixer
D/A converterA/D converter
FM synthesizer CD-ROM
Bus
/dev/dsp
/dev/sequencer /dev/cdrom
/dev/dsp
/dev/mixer/dev/mixer
Lab. Comm. Netw Arch. programming advices 16
Programming the Sound Card: Mixer
� Look into soundcard.h
� /dev/mixer : Controls the volume of all devices� Also: controls the volumes of internal processes
� Output of /dev/sequencer
� Microphone input
� CD input
� Line input
� Microphone output
� ...
� Accepts only ioctl (no write or read )� The operations over /dev/mixer can be made over /dev/dsp
� Not necessary to open both
Lab. Comm. Netw Arch. programming advices 17
Programming the Sound Card: DSP
� /dev/dsp : Converter analog/digital (sampling and quantification) and digital/analog� There is in general only one� Can be opened only by one program� The card usually provides a buffer of 64 KBytes
� Managed in units called “fragments”
� Size of the buffer / fragments configurable
� Read: The reading process is blocked until the desi red
bytes arrive�In reality, in multiples of fragments
� Write: no blocking�At least until all the buffers of the card are filled
Lab. Comm. Netw Arch. programming advices 18
Programming the Sound Card: Example I
int ioctl_arg; /* arguments for ioctl */
/* open the audio device */LLAMA ((*descDsp) = open("/dev/dsp", O_RDWR),“Failure when opening /dev/dsp“);
/* set the sampling parameters */ioctl_arg = format;LLAMA(ioctl((*descSnd), SNDCTL_DSP_SETFMT, &ioctl_a rg),“Failure when setting the sample size”
);/* 8 is PCM (with linear quantification of 8 bits);
16 is PCM with 16 bits signed little endian; see /usr/include/linux/soundcard.h for more possibilitie s */ if (ioctl_arg != format)perror(“Not possible to select the desired sample
size");
Lab. Comm. Netw Arch. programming advices 19
Programming the Sound Card:Example II
� SNDCTL_DSP_SETFMT –see soundcard.h for examples
� SNDCTL_DSP_CHANNELS� SNDCTL_DSP_SPEED� Duplex: LLAMA (ioctl (descSnd),
SNDCTL_DSP_SETDUPLEX, 0), “Failure to put the sound card into DUPLEX mode");
� Programming the volume� LLAMA (ioctl (descSnd, MIXER_WRITE
(SOUND_MIXER_MIC), &volFinal), “Failure to execute MIXER_WRITE for MIC");
� LLAMA (ioctl (descSnd, MIXER_WRITE (SOUND_MIXER_PCM), &volFinal), “Failure to execute MIXER_WRITE for PCM");
Lab. Comm. Netw Arch. programming advices 20
Programming the Sound Card:The Fragment Size
� http://www.4front-tech.com/pguide/audio2.html
� Must adjust the fragment size to the requested response time of the application� Always a power of 2, larger or equal to 16
argFrag = 0x00000000; /* 0xMMMMSSSS => MMMM de 2^SSSS*/aux = size;aux = ( log ( (double) aux) / log (2.0));argFrag = argFrag | aux;argFrag = argFrag & 0x0000FFFF; /* to get the 16 leas t
significant bits */argFrag = argFrag | 0x7fff0000 ; /* not to limit
the maximum number of different fragments */
LLAMA (ioctl ( (*soundcardDescriptor), SNDCTL_DSP_SETFRAGMENT, &argFrag), “Failure to esta blish the fragment size in the sound card");
Lab. Comm. Netw Arch. programming advices 21
Part III. Event-based processing
(asynchronous processingof events)
Lab. Comm. Netw Arch. programming advices 22
Programming Signals
� SIGINT intercepts CTRL-C
struct sigaction infoSignal;void signalhandler (int signalReason){
/* code to be activated on a signal */};
infosignal.sa_handler = signalhandler;/* It is not necessary to manipulate the mask
.sa_mask if it is not desired to vary the signals to be blocked when handling the signal */
infoSignal.sa_flags = 0;LLAMA (sigaction (signalCode, &infoSignal, NULL),
"Error when installing signal");
Lab. Comm. Netw Arch. programming advices 23
Select
� Different from asynchronous I/O: (blocking read)� Different from asynchronous I/O (periodic check by p olling)� Select = I/O multiplexing � Select waits for the first descriptor that changed its status (in
read or write), � … or wait until ceratin time is expired.
#include <sys/time.h>#include <sys/types.h>#include <unistd.h>
int select(int n, fd_set *readfds, /*read file descriptors set */fd_set *writefds, /*write file descriptors set */fd_set *exceptfds, /* exceptions set*/struct timeval *timeout /* timeout value */ );
Lab. Comm. Netw Arch. programming advices 24
Example of use of select/* Ex: generate a set of descriptors to allow await ing for data
which is supposed to arrive on descriptor 5 and 8.Maximum waitin time is 10 seconds. */
fd_set conjunto_lectura;struct timeval tv;
/* define 10 seconds waiting time */tv.tv_sec = 10;tv.tv_usec = 0;
/* configurar el conjunto de lectura */FD_ZERO(&conjunto_lectura); /* reset the variable that conta ins
descriptors */FD_SET(5, &conjunto_lectura); /* turn on filedes # 5 on
descriptor variable */ FD_SET(8, &conjunto_lectura); /* turn on filedes # 8 on
descriptor variable */
LLAMA (res = select (9 , &conjunto_lectura, NULL , NULL , &tv));
Lab. Comm. Netw Arch. programming advices 25
Example of use of select
� Checking the resultsif (res == 0) { /* 10 seconds elapsed and
timer expired */
else {
if ( FD_ISSET (5, &conjunto_lectura) == 1)
{ /* received data on descriptor 5 */ }
if ( FD_ISSET (8, &conjunto_lectura) == 1)
{ /* received data on descriptor 8 */ }
� If you have to call select again, start from th beinning: generate descr. sets, set the timer…
Lab. Comm. Netw Arch. programming advices 26
Activating a Periodic Operation
�Always use absolute time references (not relative ones)
� Determine a start time t 0
� The n-th repetition of an action of the repetitive process T must be activated at time: t n = t0 + n*T
� Look at the current time t; calculate t n
� Program select to wait t n - t time units (ticks)
Lab. Comm. Netw Arch. programming advices 27
Create multiple processes
value = fork();
if (value==0){/* child */
dspProcess(dspDescriptor, serviceParams, datDsp);}
else if (value <0){
LLAMA (-1, "Error when executing fork");}
else { /* parent */
pidChild = value;networkProcess(serviceParams, datDsp,
presentPackets, SSRC);
}
Lab. Comm. Netw Arch. programming advices 28
Part IV. Time-related functions
Lab. Comm. Netw Arch. programming advices 29
Accessing the Time
#include <sys/time.h>#include <unistd.h>
struct timeval timeVar;long seconds, microseconds;
LLAMA (
gettimeofday (&timeVar, NULL),"Failure in gettimeofday");
seconds = timeVar.tv_sec;microseconds = timeVar.tv_usec;
Lab. Comm. Netw Arch. programming advices 30
Activating a Periodic Operation
� Always use absolute time references (not relative ones)� Determine a start time t 0� The n-th repetition of an action of process T must b e
activated at time: t n = t0 + n*T� Look at the current time t; calculate t n
� Wait with nanosleep tn - t
struct timespec delay;delay.tv_nsec = (long) Value1;delay.tv_sec = (time_t) Value2;
LLAMA (nanosleep (&delay, NULL)),
"Nanosleep interrupted");
Lab. Comm. Netw Arch. programming advices 31
Part V. Memory management
Lab. Comm. Netw Arch. programming advices 32
Referencing objects in IPC� If you want to exchange data between any two proces ses you
typically have to use IPC� Before you send or receive between processes you have to
create a special IPC structure (e.g. with semget, shm get) � IPC structures are managed by the kernel � Each structure is referred to by its identifier.� Your process must know the identifier in order to be able to use
it. � During creation of a structure a key is provided
(type key_t )� The system converts the key into a unique identifier.� IPC_PRIVATE key can be defined to obtain a brand new identifier
parent: IPC_PRIVATE ���� fork (parent/child share it)
� Identifiers are unique, assigned in increasing order to avoid accidental re-use by a different process
Note: keys can be created with a ftok function (need pathname+integer)
Lab. Comm. Netw Arch. programming advices 33
Shared Memory and Semaphores
� Semaphores:� Create (or used an already created) key file� With the file, generate a key� With the key, open the semaphore in your process
� Distinct processes can access the same semaphore if they use
the same key� Configure the semaphore if necessary� Use the semaphore
� Once opened, different child processes can use it
� Shared Memory� Create key file� With the file, generate a key� With the key, create shared memory ( shmget )� With the shared memory identifier, associate it to the space in
your process ( shmat )� Release the shared memory ( shmdt )
Lab. Comm. Netw Arch. programming advices 34
Shared Memory and Semaphores
� Different semantics (although often related)� If you want to mutually exclude access to memory,
we can protect it with a semaphore
� Similar usage� Key files
� Can create one key and delete itif (NULL == (fkey = fopen (fKey1, "w")))
{LLAMA (-1, "Failure to create key file");
}fclose (fkey);
� KeysLLAMA (key = ftok (fkey, 'a'), "Failure in
ftok");
Lab. Comm. Netw Arch. programming advices 35
Shared Memory and Semaphores
� Create shared memory (semaphore is similar)LLAMA (sharedMemId = shmget (key, memSize,
IPC_CREAT | 0x1C0), "Error reserving memory");
� For semaphores, must configure initial value/* initialize the semaphore to one: prepare
for mutual exclusion */
semUnion.val = 1; /* release semaphore */
LLAMA (semctl (semaphoreId, 0, SETVAL, semUnion), "Failure to establish semaphore state");
Lab. Comm. Netw Arch. programming advices 36
Shared Memory and Semaphores
� In all child processes which will use shared memory , it is necessary to call sh mem attach:� LLAMA ((int) ptrToMem = shmat (sharedMemId, NULL,
0), “error shmat");/* request shared memory in read-only mode */
� In the semaphores, must define the operations to realize/* construct take semaphore and release
semaphore */takeSemaphore.sem_num =
releaseSemaphore.sem_num = 0;/* the first semaphore, which is the only one
created */takeSemaphore.sem_op = -1;releaseSemaphore.sem_op = 1;
Lab. Comm. Netw Arch. programming advices 37
Part VI. Buffer management
Lab. Comm. Netw Arch. programming advices 38
Ring buffer
Firstavailablepacket
Firstavailablespace
Firstavailablepacket
Firstavailablepacket
FirstavailablespaceFist
availablespace
Number ofusedzones = 5
Number ofusedzones = 6
Number ofusedzones = 0
Lab. Comm. Netw Arch. programming advices 39
Ring Buffer
/* returns a pointer to the beginning of the ring buffer region */
void * createRingBuffer (int numberOfZones, intsizeOfZone);
/* returns a pointer to the first available space, or NULL if there are no available space. Your application has to consider the case in which there are no space left*/
void * allocateSpace (void * buffer);
/* return a pointer to the first available packet, or NULL if there are not packets available. Your applicationhas to consider the case in which there are no available packets */
void * allocatePacket (void * buffer);
/* use this function before killing the process */void freeBuffer (void *bufferId);
Firstavailablepacket
Firstavailablespace
Number ofusedzones = 5
Lab. Comm. Netw Arch. programming advices 40
Part VII. Networking
Lab. Comm. Netw Arch. programming advices 41
Communication: Sockets
� Programming sockets
� Can use the library for TCP and UDP socket from “Internetworking With TCP/IP Vol. 3: Client-Server Programming And Applications. Linux/POSIX Sockets Version", D. E. Comer, D. L. Stevens� Available on the web page of the lecture
� Try also another one (alternative) if you want to
� Always check standard commands with manual (man) page
Lab. Comm. Netw Arch. programming advices 42
Socket Programming: TCP (client)
int connectTCP (const char *host, const char *service)
� Allows to open a socket for communication with a server (which must already be up and in a waiting state)� host translated using getserverbyname ()
� For IPv6 it is better to use getaddrinfo ()
� service can be a service name or the name of a port (std. service names in /etc/services )
� Returns the socket which can be used to write or read data from the server� Can execute read and write on that socket
Lab. Comm. Netw Arch. programming advices 43
Socket Programming: UDP (client)
int connectUDP (const char *host, const char *service )
� Creates a binding, so that it is not necessary to indicate where to send a packet to (e.g., in a sendto )
� Does not send data (with write ) untill there is someone listening on the other side
Lab. Comm. Netw Arch. programming advices 44
Socket Programming (server)
� int passiveTCP (const char *service, int qlen)
� To open a socket in a server, waiting for a client to connect� service is the service name or a port� qlen : maximum number of pending connections to have in a
given moment� Returns the socket identifier on which connections are awaited
� that means, right after a listen� must make an accept
socketDesc = accept((*socketReturnedByPassiveTCP), (struct sockaddr *) &clientInfo, &sizeInfo);
�Blocks until a client is connected� Then, read and write to socketDesc
� int passiveUDP (const char *service)
� Returns a socket ready to receive data� read , blocking until data arrive
Lab. Comm. Netw Arch. programming advices 45
Part VIII. Enhancements
Lab. Comm. Netw Arch. programming advices 46
IPv6� Reference: RFC 3496. Basic Socket Interface
Extensions for IPv6.� You can look at numerous examples in the Internet� Adapt the software to manage the connections
� Use getaddrinfo
� Hint: IPv6 protocol
� struct sockaddr_in6 ipv6addr;
� Use the first returned address
� if( (error = getaddrinfo(NULL, service,
&hints, &res)) ) ...
� sockRes = socket(res ����ai_family,
res ����ai_socktype, res ����ai_protocol)
� In the remaining code� char clientIPaddress[INET6_ADDRSTRLEN];
Lab. Comm. Netw Arch. programming advices 47
Adaptation to IPv6
� If you want to have double protocol stack -enabled application (both IPv4 and IPv6):
� Steps� Adapt code to manage connections
� Use getaddrinfo
�It’s neutral - does not prefer a certain protocol (IPv4/IPv6)
� In connect , use the first returned address
�The user could write the IP address directly, being able to select the protocol type
Lab. Comm. Netw Arch. programming advices 48
Select
� Passive ... Listen to all the addresses.FD_ZERO(&rfds);n = -1;for(i=0;i<num_sockets;i++) {
FD_SET(socketsUDP[i], &rfds); n = MAX(n, socketsUDP[i]);
}
/* call which blocks when listening for the recepti on of some packets on one of the sockets */
LLAMA(select(n+1, &rfds, NULL, NULL, NULL),"Failure to execute select on the receiving sockets ");
for(i=0;i<num_sockets;i++) { /* we are interested in that socket on which someth ing has
arrived */if( FD_ISSET(socketsUDP[i], &rfds)){
socketUDP = socketsUDP[i];break;
}}
Lab. Comm. Netw Arch. programming advices 49
Operations on Sockets
� Asynchronous reception/* each time a message arrives at the
socket socketTCP, a SIGIO signal is generated, which must be handled accordingly */
LLAMA (fcntl (socketDesc, F_SETOWN, getpid()), "Error in fcntl");
LLAMA (fcntl (socketDesc, F_SETFL, FASYNC), "Error in fcntl");
� Non-blocking receptionLLAMA (fcntl (socketDesc, F_SETFL,
O_NONBLOCK), “Failure in fcntl”);
Lab. Comm. Netw Arch. programming advices 50
Multicast
� IPv4: Fill in the structure ip_mreq� struct ip_mreq mreq_ipv4;
� mreq_ipv4.imr_multiaddr = dirMcastIPv4 /* a struct in_addr */;
� mreq_ipv4.imr_interface.s_addr = INADDR_ANY;
� IPv6: � struct ipv6_mreq mreq_ipv6;
� mreq_ipv6.ipv6mr_multiaddr = ((structsockaddr_in6 *)res->ai_addr)->sin6_addr;
� mreq_ipv6.ipv6mr_interface = if_nametoindex( "eth0" );
� Do not hesitate to study source files of many examples available in the Internet.... but be carefull (quality is not always top)