- 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
0to 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
delimitersin a string and replaces it withNULL delimitersis a string, each character is interpreted as a distinct delimiter- Returns the beginning of the original string, sets
sourceto 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
-afterwoahwithNULL - returns a pointer to the
winwoah - sets
currto point to thetinthis is cool
- the
execfamily -<unistd.h>-
A group of c functions that can be used to run other programs
-
Replaces the current process with the new program
-
execlexecl(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:
-
execlpexeclp(path, command, arg0, arg1, ... NULL)- Works like
excel,except it uses $PATH environment variable for command
- Works like
-
execvpexecvp(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
intparameter
- 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
signaltopid
- Sends
$ killall [-signal] process_nameNote: 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 - 1characters from file streamfand stores it ins, appendsNULLto 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.stdinis 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_tvariables, we can use functions intime.hto 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
errnoerrnois an int variable that can be found in <errno.h>- Use
strerrorin (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
chownandchgrpcommand 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
-gflags 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-gflag with gcc -
basic usage:
$ gdb program- starts a
gdbshell from which you can run your program
- starts a
-
Commands from in the
gdbshellrun: runs the program until it ends/crashes/gets a signallist: shows the lines of code run around a crashprint var: prints the value of ofvarat 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
-gin order to use valgring (and similar tools) -
basic usage:
$ valgrind --leak-check=yes ./program
calloc(size_t n, size_t x)- allocates
n * xbytes of memory - ensures every bit is 0
realloc(void *p, size_t x)- changes the amount of memory allocated for a block to
xbytes pmust 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
xis smaller than the original size of the allocation, the extra bytes will be released - if
xis 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
xbytes 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/callocshould have a corresponding call tofree
calloc(size_t n, size_t x)- allocates
n * xbytes 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
upersists 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,
sis a variable of typestruct {int a; char x;} -
we use the
.operator to access values inside a structs.a = 10; s.x = '@'; -
size of
structmay 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;
};-
foois a prototype for thestructstruct foo s; -
gcc will appropriately copy values between same non-anonymous
structs -
common practice (in standard C libraries) to not
typedefastructbecause it hides stuff -
normally don't declare
structs in main, typically outside all functions -
can also declare
structs in header files -
.binds before* -
to access data from a
structpointer you would do:
struct foo *p;
p = &s;
(*p).x;
p->x; //c shorthand for (*p).xMr.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 longWhy?
- allows code to work on different machines (known as portability)
- defines appropriately for every machine
- technically: can
typedefatypedef
- 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