- a piece of memory that your program is going to use to transfer data
- unlike a pipe it will need a lot more information on the operating system
- there are 3 things associated with a socket that makes it unique
- Protocol (2)
- 2 main protocols you will deal with
- Transmission Control Protocol (TCP) or just Stream Protocol
- if you send data to another machine using TCP
- either the data will be sent in entirety in the order you sent
- or you will get an error
- 2 packets might take different paths to the same place
- if packets dont get there, they can ask to send the packet again
- if you send data to another machine using TCP
- User Datagram Protocol (UDP)
- not verified (no handshake)
- maybe someone listening, maybe not
- just sends data out
- does not worry about rearranging packets (not in order)
- WONT request packets missing
- much faster
- used all the time for streaming media and games
- Transmission Control Protocol (TCP) or just Stream Protocol
- 2 main protocols you will deal with
- Port (65,536)
- that is what allows you to have multiple sockets associated with the same IP Address
- ex: every different web browser tab is a socket with different ports
- some are designated for specific usage
- port 80 is for web traffic
- Incoming/Outgoing Addresses (I.P. Addresses)
- externally provided
- generally each computer has just 1
- Protocol (2)
- Operating System
- Endian-ness (Integer size)
- Somehow connected
7)Application - most abstract
...
1)Physical Hardware - most concrete
-1) Peer-To-Program (not exactly Server/Client)
- C_0 <---> C_1
- Direct connection between clients
- Good for well-structured interactions
- Single Server
- 1 server
- Handles all connections
- Handles all communication
- 1 server
- Forking Server
- 1 main server
- Handles all connections
- Creates subservers to handle all communication
- 1 main server
- Dispatch Server
- 1 main server
- Handles all connections
- Handles all incoming data
- Subservers handle all outgoing data
- Main server routes data to subservers
- 1 main server
- Semaphore operations
- Create a semaphore
- Set an initial value
- Remove a semaphore
Up(S)
/V(S)
- atomic- Release the semaphore to signal you are done with its associates resource
- Pseudocode
S++
Down(S)
/P(S)
- atomic- Attempt to take the semaphore
- If the semaphore is 0, wait for it to be available
- Pseudocode
while (S == 0) { block } S--;
- Shared Memory
<sys/shm.h>
,<sys/ipc.h>
,<sys/types.h>
- A segment of heap memory that can be accessed by multiple processes
- Shared memory is accessed via a key that is known by any process that needs to access it
- Shared memory does not get released when a program exits
- 5 Shared memory operations
- Create the segment (happens once) -
shmget
- Access the segment (happens once per process) -
shmget
- Attach the segment to a variable (once per process) -
shmat
- Detach the segment from a variable (once per process) -
shmdt
- Remove the segment (happens once) -
shmctl
- Create the segment (happens once) -
int main() {
int fd;
char line[100];
mkfifo("mario", 0640);
fd = open("mario", O_RDONLY);
printf("fifo open!\n");
remove("mario);
while(read(fd, line, sizeof(line)))
printf("read: [%s]\n", line);
}
- Managing Sub-Processes
fork() - <unistd.h>
- Creates a separate process based on the current one, the new process is called a child, the original is the parent
- The child process is a duplicate of the parent process
- All parts of the parent process are copied, including stack and heap memory, and the file table
- Returns
0
to the child and the child's pid, or-1
(errno), to the parent
strsep - <string.h>
-
Parse a string with a common delimiter
strsep( source, delimiters)
- Locates the first occurence of any of the specified
delimiters
in a string and replaces it withNULL
delimiters
is a string, each character is interpreted as a distinct delimiter- Returns the beginning of the original string, sets
source
to the string starting at 1 index past the location of the newNULL
- Locates the first occurence of any of the specified
-
Example:
-
char line[100] = "woah-this-is-cool";
char *curr = line;
char * token;
token = strsep(&curr, "-");
- replaces the
-
afterwoah
withNULL
- returns a pointer to the
w
inwoah
- sets
curr
to point to thet
inthis is cool
- the
exec
family -<unistd.h>
-
A group of c functions that can be used to run other programs
-
Replaces the current process with the new program
-
execl
execl(path, command, arg0, arg1, ... NULL)
path
- The path to the program (ex
"/bin/ls"
)
- The path to the program (ex
command
- The name of the program (ex:
"ls"
)
- The name of the program (ex:
arg0 ...
- Each command line argument you wish to give the program (ex:
"-a", "-l"
) - The last argument must be NULL
- Each command line argument you wish to give the program (ex:
-
execlp
execlp(path, command, arg0, arg1, ... NULL)
- Works like
excel
,except it uses $PATH environment variable for command
- Works like
-
execvp
execvp(path, argument_array)
argument_array
- Array of strings containing the arguments to the command
argument_array[0]
must be the name of the program- Last entry must be NULL
-
strsep - <string.h>
- Parse a string with a common delimiter
-
static void sighandler() {
if (signo == SIGINT) {
printf("haha! Can't touch this!\n");
}
if (signo == SIGSEGV) {
printf("nothing too see here..\n");
exit(0);
}
}
int main() [
//...
signal(SIGINT, sighandler);
signal(SIGSEGV, sighandler);
//...
}
- Signal handling in c program
<signal.h>
sighandler
- To intercept signals in a c program you must create a signal handling function
- Some signals (like SIGKILL, SIGSTOP) cannot be caught
static void sighandler(int signo)
- Must be
static
- Must be
void
- Must take a single
int
parameter
- Must be
- Signals
- Limited way of sending information to a process
- Sends an integer value to a process
$ kill
- Command line utility to send a signal to a process
$ kill pid
- Sends signal 15 (SIGTERM) to
pid
- Sends signal 15 (SIGTERM) to
$ kill -signal pid
- Sends
signal
topid
- Sends
$ killall [-signal] process_name
Note: killing one of the init processes shuts down your computer
- Signals in c programs
<signal.h>
- kill
kill(pid, signal)
- Can use to catch and change behavior when signals recieved
- kill
- Processes
- Every running program is a process
- A process can create subprocesses, but these are no different from regular processes
- A processor can handle 1 process per cycle (per core)
- "Multitasking" appears to happen because the processor switches between all the active processes quickly
sscanf - <stdio.h>
- Reads in data from a string using a format string to determine types
sscanf(char *s, char * format, void * var0, void * var1, ...)
- Copies the data into each variable
- Example usage:
int x; float f; double d;
sscanf(s, "%d %f %lf", &x, &f, &d);
-
Command Line Arguments:
int main (int argc, char * argv[])
- Program name is considered the first command line argument
argc
- number of command line arguments
argv
(argument vector)- array of command line arguments as strings
-
fgets - <stdio.h>
- Read in data from a file stream and store it in a string.
fgets( char * s, int n, FILE * f);
- Reads at most
n - 1
characters from file streamf
and stores it ins
, appendsNULL
to the end.
- Reads at most
- Stops at newline, end of file, or the byte limit.
- File stream
File *
type, more complex than a file descriptor, allows for buffered input.stdin
is aFILE *
variable
- Example:
fgets(s, 100, stdin)
All directories are 4096 bytes and are executable.
Directories
- A linux directory is a file containing the names of the files within the directory along with basic information, like file type.
- Linux will increase the directory size if needed.
opendir - <dirent.h>
- open a directory file
- This will not change the current working directory (cwd), it only allows your program to read the contents of the directory file
opendir(path)
- Returns a pointer to a directory stream (
DIR *
)
- Returns a pointer to a directory stream (
readdir - <dirent.h>
readdir(dir_stream)
- Returns a pointer to the next entry in a directory steam, or NULL if all entries have alreadty been returned.
-
struct dirent - <sys/types.h>
- Returns a pointer to the next entry in a directory steam, or NULL if all entries have alreadty been returned.
-
stat - <sys/stat.h>
-
Get information about a file (metadata)
stat(path, stat_buffer)
-
stat_buffer
- Must be a pointer to a
struct stat
- All the file information gets put into the stat buffer
- Some of the fields in
struct stat
:st_size
- file size in bytes
st_uid
,st_gid
- user id, group id
st_mode
- file permissions
st_atime
,st_mtime
- last access, last modification
- these are
time_t
variables, we can use functions intime.h
to make sense of themctime(time)
- Must be a pointer to a
-
lseek - <unistd.h>
-
Set the current position in an open file
lseek(file_descriptor, offset, whence)
-
offset
- Number of bytes to move the position by, can be negative (has to be int)
-
whence
- Where to measure the offset from
- SEEK_SET
- offset is evaluated from the beginning of the file
- SEEK_CUR
- offset is relative to the current position in the file
- SEEK_END -offset is evaluated from the end of the file
-
Returns the number of bytes the current position is from the beginning of the file , or -1 and sets errno
-
printf("O_RDONLY: \t%d\n", O_RDONLY); // 0
printf("O_WRONLY: \t%d\n", O_WRONLY); // 1
printf("O_RDWR: \t%d\n", O_RDWR); // 2
printf("O_CREAT: \t%d\n", O_CREAT); // 64
printf("O_EXCL: \t%d\n", O_EXCL); // 128 if a file exists and you want to create it, will return an error
printf("O_TRUNC: \t%d\n", O_TRUNC); // 512 starts at beginning of file
printf("O_APPEND: \t%d\n", O_APPEND); // 1024 starts at end of file
// each constant in decimal is a 1 with a bunch of 0s after
// bitwise or (|) will combine them
If you do not set the mode argument when creaing a file, you will get random permissions.
-
umask - <sys/stat.h>
- set the file creation permission mask
- By default, created files are not given the exact permissions provided in the mode argument to open. Some permissions are automatically shut off
- mask: 000 000 010 (write for others is shut off) - ~mask: 111 111 101 (bit wise negation) - mode: 110 110 110 - ~mask & mode : 110 110 101 (bit wise negation of mask, bitwise and mode) - the default linux mask is 002 - umask(0) //no mask
-
read - <unistd.h>
- read data from a file
read(fd, buff, n)
- read n bytes from fd's file into buffer
- returns the number of bytes actually read. Returns -1 and sets errno if unsuccessful.
- buff must be a pointer
char buff[100];
int fd = open("foo", 0_RDONLY);
read(fd, buff, sizeof(buff));
-
write - <unistd.h>
- write data to a file
write(fd, buff, n)
- write n bytes to fd's file from buffer
- returns the number of bytes actually written. Returns -1 and sets errno if unsuccessful.
- buff must be a pointer
-
close
- closes file
- returns -1 and sets errno if unsuccessful.
close(fd)
- File Table (cont.)
- Contains where you are in a file
- Flushing buffers? (smth w/ newlines)
- ex:
FD | Name | Path | Size | ... |
---|---|---|---|---|
0 | stdin | |||
1 | stdout | |||
2 | stderr | |||
3 | goo | |||
4 | boo |
open - <fcntl.h>
- Add a file to the file table and returns its file descriptor
- If open fails, -1 is returned, extra error information can be found in
errno
errno
is an int variable that can be found in <errno.h>- Use
strerror
in (string.h) on errno to return a string description of the error
- How to use errno example:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
int main() {
int fd;
fd = open("tobe", O_RDONLY);
if ( fd < 0) {
printf("errno: %d error: %s\n", errno, strerror(errno) );
return 0;
}
printf("fd: %d\n", fd);
printf("errno: %d error: %s\n", 6, strerror(6) );
return 0;
}
open( path, flags, mode)
mode
- Only used when creating a file
- Set the new file's permissions using a 3 digit octal number
flags
- Determine what you plan to do with the rile, use the following constants and combine with |:
- O_RDONLY
- O_WRONLY
- O_RDWR
- O_APPEND
- O_TRUNC
- O_CREAT
- O_EXCL: when combined with O_CREAT, will return an error if the file exists
- Determine what you plan to do with the rile, use the following constants and combine with |:
-
File Permissions
-
3 types of permissions
- read, write, execute
-
Permissions can be represented as 3-digit binary numbers, or 1-digit octal numbers
100
<==>4
=> read only111
<==>7
=> read, write, execute
-
There are 3 permission "areas"
- user, group, others
- Membership in each "area" is mutually exclusive
- The creator of the file is the default setting for the user and group of a file
- user, group, others
-
chmod permissions file
- Command line utility to change file permissions
- The owner of a file (or root) can always change permissions
- File ownership and group can be changed with the
chown
andchgrp
command line utilities
-
-
File Table
- A list of all files being used by a program while it is running
- Contains basic information like the file's location and size
- The file table has limited space, which is a power of 2 and commonly 256
getdtablesize()
will return the file table size- Each file is given an integer index, starting at 0, this is the file descriptor
- There are 3 files always open in the table:
- 0 or STDIN_FILENO: stdin
- 1 or STDOUT_ FILENO: stdout
- 2 or STDERR_FILENO: stderr
- Other base formatting characters for
printf
:%o
: octal integer%x
: hexadecimal integer
- You can define native integers in bases 2, 8, and 16 by using the following prefixes
0b
: binary0
: octal0x
: hexadecimal
Note: Why do programmers always mix up Holloweeen and Christmas? ... Because 31 Oct is the same as 25 Dec :P
- Evaluated on every bit of a value
~x
- Negation
- Flip every bit of
x
a | b
- Bitwise or
- Perform logical or for each pair of bits in (a, b)
a & b
- Bitwise and
- Perform logical and for each pair of bits in (a, b)
a ^ b
- Bitwise xor
- Perform logical xor for each pair of bits in (a, b)
char i = 13
i: 00001101
!i: 0
~i: 11110010
char x = 8;
x: 00001000
~i | x : 11111010
~i & x : 00000000
// swapping a and b
a = a ^ b // a contains bits not in common
b = a ^ b // b now contains a
a = b ^ a // a now contains b
// swapping cont.
r = a ^ b
b = r ^ b => a ^ b ^ b = 0 ^ a
a = r ^ b => a ^ b ^ a = 0 ^ b
- Swapping Bits Using Only Bitwise Operators
a | b | a = a ^ b | b = a ^ b | a = b ^ a |
---|---|---|---|---|
T | T | F | T | T |
T | F | T | T | F |
F | T | T | F | T |
F | F | F | F | F |
ifeq ($(DEBUG), true)
CC = gcc -g
else
CC = gcc
endif
all: main.o definitions.o
$(CC) -o program main.o definitions.o
main.o: main.c headers.h
$(CC) -c main.c
definitions.o: definitions.c headers.h
$(CC) -c definitions.c
run:
./program
memcheck:
valgrind --leak-check=yes ./program
clean:
rm *.o
rm program
-
can now run this command to make with
-g
flags in order to debug:$ make DEBUG=true
-
convention to use all caps variables in makefile
-
$(<variable>)
is how you use variables in make -
can now easily run valgrind using:
$ make memcheck
-
to use
gdb
, you must compile using the-g
flag with gcc -
basic usage:
$ gdb program
- starts a
gdb
shell from which you can run your program
- starts a
-
Commands from in the
gdb
shellrun
: runs the program until it ends/crashes/gets a signallist
: shows the lines of code run around a crashprint var
: prints the value of ofvar
at the timebacktrace
: shows the current stackbreak lineNum
: creates breakpoint at a line
-
Running a program in pieces
run
: restarts the programcontinue
: run the program until the next breakpoint/crash/endnext
: run the next line of the program onlystep
: run the next line of the program, if that is a function call, run only the next line of that function
-
tool for debugging memory issues in C programs
-
you must compile with
-g
in order to use valgring (and similar tools) -
basic usage:
$ valgrind --leak-check=yes ./program
calloc(size_t n, size_t x)
- allocates
n * x
bytes of memory - ensures every bit is 0
realloc(void *p, size_t x)
- changes the amount of memory allocated for a block to
x
bytes p
must point to the beginning of a block- returns a pointer to the beginning of the block (this is not always the same as
p
) - if
x
is smaller than the original size of the allocation, the extra bytes will be released - if
x
is larger than the original size then either:- if there is enough space at the end of the original allocation, the original allocation will be updated
- if there is not enough space, a new allocation will be created, containing all the original values; the original allocation will be freed
malloc(size_t x)
-
allocates
x
bytes of heap memory -
returns the address at the beginning of the allocation
-
returns a
void *
-
can be used like an array:
int *p; p = malloc(5 * sizeOf(int));
free(void * p)
- releases dynamically allocated memory
- has one parameter, a pointer to the beginning of a dynamically allocated block of memory
- cannot free a portion, only the entire thing
- every call to
malloc
/calloc
should have a corresponding call tofree
calloc(size_t n, size_t x)
- allocates
n * x
bytes of memory - ensures every bit is 0
- as a data structure
- first in, last out
- terminology: push, pop
- associated with function calls
- stores all normally declared variables (including pointers and structs), arrays, and function calls
- functions are pushed onto the stack in the order they are called, and popped off when completed
- when a function is popped off the stack, the staclk memory associated with it is released
- only one stack
- stores dynamically allocated memory
- allocated at runtime
- data will remain in the eap until it is manually released (or the program terminates)
- hence no garbage collector like in Java
struct login u = new_account(4190);
Order of operations when run:
- allocates memory necessary for
u
- runs
new_account(4190)
- copies the values of the returned struct into space allocated for
u
- returned struct goes away and
u
persists because it is in themain()
function
Using struct as a parameter vs. pointer:
- copies argument into parameter variable
- edits the copy
- only in scope of the function
struct {int a; char x;} s;
-
(kind of like objects, but not advised to think of it this way)
-
in this example,
s
is a variable of typestruct {int a; char x;}
-
we use the
.
operator to access values inside a structs.a = 10; s.x = '@';
-
size of
struct
may not necessarily equal the sum of sizes of the values, might be a little more -
"anonymous" struct, no name
struct foo {int a; char x;};
struct foo {
int a;
char x;
};
-
foo
is a prototype for thestruct
struct foo s;
-
gcc will appropriately copy values between same non-anonymous
struct
s -
common practice (in standard C libraries) to not
typedef
astruct
because it hides stuff -
normally don't declare
struct
s in main, typically outside all functions -
can also declare
struct
s in header files -
.
binds before*
-
to access data from a
struct
pointer you would do:
struct foo *p;
p = &s;
(*p).x;
p->x; //c shorthand for (*p).x
Mr.Zamansky and Hunter Daedalus Program Talk
Google Mentorship Talk
-
used to make executable
-
works for not only C
-
Java Compiler and JVM do stuff for you, so it doesn't give you executables (gives machine code instead)
-
good practices
- separate compilations steps for each *.c file
- run
- clean
-
only recompiles modified files
-
dependencies should only be one *.c file and other header *.h files
-
example makefile:
all: main.o definitions.o gcc -o program main.o definitions.o main.o: main.c headers.h gcc -c main.c definitions.o: definitions.c gcc -c definitions.c run: ./program clean: rm *.o
-
make will stop at first error
In char *strncpy(char *dest, const char *src, size_t n);
what is the type size_t
?
Usage:
typedef real_type new_name;
Examples:
typedef unsigned long size_t;
size_t x = 139; //x is really an unsigned long
Why?
- allows code to work on different machines (known as portability)
- defines appropriately for every machine
- technically: can
typedef
atypedef
- variable type for storing memory addresses
- unsigned integer type
- 8 bytes large
- when used as parameter
- pass by value
- address copied into the parameter and points to the same thing
- argument remains unchanged
- parameter's memory allocated in space allocated for the associated function
- pass by value
Types | Size |
---|---|
char | 1 byte |
int | 4 bytes |
short | 2 bytes |
long | 8 bytes |
float | 4 bytes |
double | 8 bytes |
- Instructions go in (in bits)
- Stuff happens in the middle
- Out comes the result
- 2GHz = 2 billion input/output cycles per second
- Gets hot because electrical signals all go through the same pathway
- Reads bits instruction, all 64-bits at once
- Cannot break up memory addresses
- This is why a memory address can only be 8 bytes at most (8 * 8 = 64)
.java --> .class --> JVM --> OS --> Hardware
.c --> Executable --> OS --> Hardware
- OS allocates memory for programs and keeps track
- Programs cannot access memory outside of their allocation
- If the program tries to --> Segmentation Fault