My Notes From My Notebook
My Blog On Mars
My Blog On Mars
Nov 30th
You’ve probably known that repository is usually divided into three separate directories. Short explanations, for the folks who haven’t used them :
Branch:
Every time you release a major version, it gets a branch created. This allows you to do bug fixes and make a new release without having to release the newest – possibly unfinished or untested – features. For instance you want to add feature X, but you are not sure if it will work or not and you don’t want to merge it to trunk without testing then you’ll create a separate branch and do your changes at this branch then you’ll merge it to the trunk.
Trunk: This is the main development place. The commits that you are applying must effect here. If you created a branch then you can merge with branch and trunk later on.
Tag: A definite time in the development. This is usually the point in time on the trunk or a branch that you wish to preserve. There can be two reasons for creating tags, either you have a major release of the software like alpha, beta, RC or RTM, or you want to have the most stable point of the software before major revisions on the trunk were applied.
In git branching, tagging and creating trunks are fairly easy:
To create a tag:
git tag -a tag_name
“-a” : make an unsigned tag object
If you want create a signed tag object then you can use with “-s”
To list the tags:
git tag -l
To show the tag message:
git show tag
To create a branch:
git branch branch_name
To switch your tree to a specific branch:
git checkout branch_name
To list the branches:
git branch
To revert back a revision:
git checkout revision_name
After you have finished implementing a new feature on a branch, you may want to merge the trunk with branch, in order to achieve this:
git merge [head]
Edit: git merge is added and a typo is fixed
Nov 28th
This brief guide is prepared for the people who knows C and have some knowledge about computer networks and protocols. This guide is mainly a summary of several resources indicated in the resources part.
For the folks who want to get more information related to some fundemental knowledge related to essentials of computer networks. Please read the following RFC’s:
UDP-RFC0768
IP-RFC791
TCP-RFC0793
Please also check the resources provided at the end of this post to get more information about the socket programming.
What are Internet Sockets?
Sockets are used for communication between endpoints in a bidirectional manner. Berkeley sockets API comprises a library for developing applications in the C programming language that perform IPC, most commonly for communications across a computer network.
There are 2 fundemental Socket types:
Some of the other socket types:
Fundemental C Structs for Sockets
addrinfo struct is used in host name lookups, and service name lookups. This is one of the first things you’ll call when making a connection. This is simply a linked-list. One common function that uses this struct is getaddrinfo(). It’ll return a pointer to a new linked list of these structures filled out with all the goodies you need.
You can force it to use IPv4 or IPv6 in the ai_family field, or leave it as AF_UNSPEC to use whatever.
You’ll see that the ai_addr field in the struct addrinfo is a pointer to a struct sockaddr.
struct addrinfo { int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc. int ai_family; // AF_INET, AF_INET6, AF_UNSPEC int ai_socktype; // SOCK_STREAM, SOCK_DGRAM int ai_protocol; // use 0 for "any" size_t ai_addrlen; // size of ai_addr in bytes struct sockaddr *ai_addr; // struct sockaddr_in or _in6 char *ai_canonname; // full canonical hostname</code> struct addrinfo *ai_next; // linked list, next node }; |
struct sockaddr holds socket address information for many types of sockets.
struct sockaddr { unsigned short sa_family; // address family, AF_xxx char sa_data[14]; // 14 bytes of protocol address }; |
sa_family can be a variety of things, but it’ll be AF_INET (IPv4) or AF_INET6 (IPv6) for everything we do in this document. sa_data contains a destination address and port number for the socket.
To deal with struct sockaddr, programmers created a parallel structure: struct sockaddr_in (“in” for “Internet”) to be used with IPv4.
A pointer to a struct sockaddr_in can be cast to a pointer to a struct sockaddr and vice-versa. So even though connect() wants a struct sockaddr*, you can still use a struct sockaddr_in and cast it.
// (IPv4 only--see struct sockaddr_in6 for IPv6)</code> struct sockaddr_in { short int sin_family; // Address family, AF_INET unsigned short int sin_port; // Port number struct in_addr sin_addr; // Internet address unsigned char sin_zero[8]; // Same size as struct sockaddr }; |
sin_zero (which is included to pad the structure to the length of a struct sockaddr) should be set to all zeros with the function memset(). Also, notice that sin_family corresponds to sa_family in a struct sockaddr and should be set to “AF_INET”. Finally, the sin_port must be in Network Byte Order.
If you have declared ina to be of type struct sockaddr_in, then ina.sin_addr.s_addr references the 4-byte IP address (in Network Byte Order).
// (IPv4 only--see struct in6_addr for IPv6) // Internet address (a structure for historical reasons)</code> struct in_addr { uint32_t s_addr; // that's a 32-bit int (4 bytes) }; |
IPv6 counterparts of the above structs are as in the following:
// (IPv6 only--see struct sockaddr_in and struct in_addr for IPv4)</code> struct sockaddr_in6 { u_int16_t sin6_family; // address family, AF_INET6 u_int16_t sin6_port; // port number, Network Byte Order u_int32_t sin6_flowinfo; // IPv6 flow information struct in6_addr sin6_addr; // IPv6 address u_int32_t sin6_scope_id; // Scope ID }; |
struct in6_addr { unsigned char s6_addr[16]; // IPv6 address }; |
struct sockaddr_storage that is designed to be large enough to hold both IPv4 and IPv6 structures. Sometimes you don’t know in advance if it’s going to fill out your struct sockaddr with an IPv4 or IPv6 address. So you pass in this parallel structure, very similar to struct sockaddr except larger, and then cast it to the type you need:
struct sockaddr_storage { sa_family_t ss_family; // address family // all this is padding, implementation specific, ignore it: char __ss_pad1[_SS_PAD1SIZE]; int64_t __ss_align; char __ss_pad2[_SS_PAD2SIZE]; }; |
All of the above structs were in header file but the following struct is in .
struct hostent { char *h_name; // Official name of host. char **h_aliases; // Alias list. int h_addrtype; // Host address type. int h_length; // Length of address. char **h_addr_list; // List of addresses from name server. #define h_addr h_addr_list[0] // Address, for backward compatibility. }; |
struct hostent defines a host computer on the Internet. The members of this structure are:
h_name Official name of the host. h_aliases A zero terminated array of alternate names for the host. h_addrtype The type of address being returned; currently always AF_INET. h_length The length, in bytes, of the address. h_addr_list A pointer to a list of network addresses for the named host. Host addresses are returned in network byte order.
Conversions
There are two types of byte ordering: most significant byte and least significant byte.
This former is called “Network Byte Order” and some machines store their numbers internally
in Network Byte Order.
There are two types you can convert: short and long.
Imagine you want to convert a long from Host Byte Order to Network Byte Order. There’s a function called htonl() that would convert it. Those functions are in header file. The following functions are
used to convert :
htons() -> “Host to Network Short”
htonl() -> “Host to Network Long”
ntohs() -> “Network to Host Short”
ntohl() -> “Network to Host Long”
An important thing, is that sin_addr and sin_port (from struct sockaddr_in) must be in Network
Byte Order .
IP Adresses
In C, there are some functions that will help you manipulating IP addresses. We’ll talk about
inet_addr() and inet_ntoa() functions.
inet_addr() converts an IP address into an unsigned long. An example:
(…)
dest.sin_addr.s_addr = inet_addr(“195.65.36.12″);
(…)
/*Remember that this is if you’ve a struct dest of type sockaddr_in*/
inet_ntoa() converts string IP addresses to long. An example:
(…)
char *IP;
ip=inet_ntoa(dest.sin_addr);
printf(“Address is: %s\n”,ip);
(…)
inet_pton, inet_ntop: Those functions are in header file. They convert IPv4 and IPv6 addresses between binary and text form.
Remember that inet_addr() returns the address in Network Byte Order – so you don’t need to
call htonl().
Headers and APIs
getaddrinfo():
NAME
getaddrinfo() – get the ip address of the node
SYNOPSIS
#include <sys/types.h> #include <sys/socket.h> #include <netdb.h> int getaddrinfo(const char *node, // e.g. "www.example.com" or IP const char *service, // e.g. "http" or port number const struct addrinfo *hints, struct addrinfo **res); |
It used to be that you would use a function called gethostbyname() to do DNS lookups. Then you’d load that information by hand into a struct sockaddr_in, and use that in your calls.
Now you have the function getaddrinfo() that does all kinds of good stuff for you, including DNS and service name lookups, and fills out the structs.
Here is an example code which will make everything clearer:
#include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> //for memset function /* The getaddrinfo() function translates the name of a service location (for example, a host name) and/or a service name and returns a set of socket addresses and associated information to be used in creating a socket with which to address the specified service. int getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res); nodename (Input) The pointer to the null-terminated character string that contains the descriptive name or address string for which the address information is to be retrieved. If the servname parameter is null, a nodename must be specified and the requested network-level address will be returned. If the nodename parameter is null, a servname must be specified and the requested service location will be assumed to be local to the caller. If the specified address family is AF_INET, AF_INET6, or AF_UNSPEC, valid descriptive names include host names. If the specified address family is AF_INET, AF_INET6, or AF_UNSPEC, the permissable address string formats for the nodename parameter are specified as defined in inet_pton(). servname (Input) The pointer to the null-terminated character string that contains the descriptive name or numeric representation suitable for use with the address family or families for which the requested service information is to be retrieved. If nodename is not null, the requested service location is named by nodename; otherwise, the requested service location is local to the caller. If the specified address family is AF_INET, AF_INET6, or AF_UNSPEC, the service can be specified as a string specifying a decimal port number. */ int main() { int status ; /* Struct addrinfo has the following structure: struct addrinfo { int ai_flags; // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST, .. int ai_family; // PF_xxx int ai_socktype; // SOCK_xxx int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6 socklen_t ai_addrlen; // length of ai_addr char *ai_canonname; // canonical name for nodename struct sockaddr *ai_addr; // binary address struct addrinfo *ai_next; // next structure in linked list }; */ struct addrinfo hints; /* The pointer to a struct addrinfo. If the parameter hints is not null, it refers to a structure containing input values that may direct the operation by providing options and by limiting the returned information to a specific socket type, address family and/or protocol. In this hints structure every member other than ai_flags, ai_family, ai_socktype and ai_protocol must be zero or a null pointer. If hints is a null pointer, the behavior will be as if it referred to a structure containing the value zero for the ai_flags, ai_socktype and ai_protocol fields, and AF_UNSPEC for the ai_family field. */ struct addrinfo *servinfo; //will point to the results memset( &hints, 0, sizeof hints ); // empty the hints struct hints.ai_family = AF_UNSPEC; //don't care if it is ipv4 or ipv6 hints.ai_socktype = SOCK_STREAM; //use TCP stream sockets hints.ai_flags = AI_PASSIVE; /* The AI_PASSIVE flag in the ai_flags member of the hints structure specifies how to fill in the IP address portion of the socket address structure. If the AI_PASSIVE flag is specified, then the returned address information will be suitable for use in binding a socket for accepting incoming connections for the specified service (that is, a call to bind()). In this case, if the nodename parameter is null, then the IP address portion of the socket address structure will be set to INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6 address. If the AI_PASSIVE bit is not set, the returned address information will be suitable for a call to connect() (for a connection-oriented protocol) or for a call to connect(), sendto() or sendmsg() (for a connectionless protocol). In this case, if the nodename parameter is null, then the IP address portion of the socket address structure will be set to the loopback address. This flag is ignored if the nodename parameter is not null. */ /* Here's a sample call if you're a server who wants to listen on your host's IP address, port 3490. Note that this doesn't actually do any listening or network setup; it merely sets up structures we'll use later: */ if( status = getaddrinfo( NULL, "3490", &hints, &servinfo ) ) { fprintf( stderr, "getaddrinfo error: %s\n", "can't get the address info" ); exit( 1 ); } //servinfo now points to a linked list of 1 or more struct addrinfos //.... do everything until you don't need servinfo anymore freeaddrinfo( servinfo ); return EXIT_SUCCESS; } |
A program which outputs the IP’s (IPv4 or IPv6) of given address:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | #include <string.h> #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <sys/types.h> #include <netdb.h> #include <arpa/inet.h> int main( int argc, char *argv[] ) { struct addrinfo hints, *res, *p; int status; char ipstr[ INET6_ADDRSTRLEN ]; void *addr; char *ipver; struct sockaddr_in *ipv4; struct sockaddr_in6 *ipv6; if( argc != 2 ){ fprintf(stderr,"usage: showip hostname\n"); exit( EXIT_FAILURE ); } memset( &hints, 0, sizeof hints ); hints.ai_family = AF_UNSPEC; // for both ipv6 and ipv4 hints.ai_socktype = SOCK_STREAM; if( ( status = getaddrinfo( argv[1], NULL, &hints, &res ) ) != 0 ){ fprintf( stderr, "getaddrinfo error: %s \n", "no address found" ); exit( EXIT_FAILURE ); } printf( "IP address for %s the host is: \n\n", argv[1] ); for( p = res; p != NULL; p = p->ai_next ){ addr = NULL; ipver = NULL; // get the pointer to the address itself // different fields in IPv4 and IPv6 if( p->ai_family == AF_INET ) { //IPv4 ipv4 = ( struct sockaddr_in * ) p->ai_addr; addr = &( ipv4->sin_addr ); ipver = "IPv4"; } else { //IPv6 ipv6 = ( struct sockaddr_in6 * ) p->ai_addr; addr = &( ipv6->sin6_addr ); ipver = "IPv6"; } inet_ntop( p->ai_family, addr, ipstr, sizeof ipstr ); printf( "%s %s\n", ipver, ipstr ); } freeaddrinfo( res ); // free the linkedlist return EXIT_SUCCESS; } |
socket():
NAME
socket() – create a socket and return a socket file descriptor
SYNOPSIS
#include <sys/types.h> #include <sys/socket.h> int socket(int domain,int type,int protocol); |
Arguments:
socket() gives you a socket descriptor that you can use in later system calls or
it gives you -1 on error (this is usefull for error checking routines).
socket() code snippet:
int socket_desc; socket_desc=socket(AF_INET,SOCK_STREAM,0); if (socket_desc==-1) perror("Create socket"); |
bind():
NAME -The bind() system call binds a socket to an address, in this case the address of the current host and port number on which the server will run.
SYNOPSIS
#include <sys/types.h> #include <sys/socket.h> int bind(int fd, struct sockaddr *my_addr,int addrlen); |
Arguments are:
bind() is used when you care about your local port (usually when you use listen() ) and its function is to associate a socket with a port (on your machine). It returns -1 on error.
You can put your IP address and your port automatically:
server.sin_port = 0; /* bind() will choose a random port*/ server.sin_addr.s_addr = INADDR_ANY; /* puts server's IP automatically */ |
An important aspect about ports and bind() is that all ports bellow 1024 are reserved. You can set a port above 1024 and below 65535 (unless the ones being used by other programs).
struct sockaddr_in address; /* type of socket created in socket() */ address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; /* 7000 is the port to use for connections */ address.sin_port = htons( 7000 ); /* bind the socket to the port specified above */ bind( socket_desc, (struct sockaddr *)&address, sizeof address ); |
connect():
NAME -establish a connection to a server or peer
SYNOPSIS
#include <sys/types.h> #include <sys/socket.h> int connect(int fd, struct sockaddr *serv_addr, int addrlen); |
Let’s see the arguments:
connect() is used to connect to an IP address on a defined port. It returns -1 on
error.
An example code snippet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | struct hostent *he; struct sockaddr_in server; int sockfd; /* resolve localhost to an IP (should be 127.0.0.1) */ if ((he = gethostbyname("localhost")) == NULL) { puts("error resolving hostname.."); exit(1); } /* * copy the network address part of the structure to the * sockaddr_in structure which is passed to connect() */ memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length); server.sin_family = AF_INET; server.sin_port = htons(7000); /* connect */ if (connect(sockfd, (struct sockaddr *)&server, sizeof(server)) { puts("error connecting.."); exit(1); } |
A connect with retry function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <sys/socket.h> #define MAXSLEEP 128 int connect_retry(int sockfd, const struct sockaddr *addr, socklen_t alen) { int nsec; /* * Try to connect with exponential backoff. */ for (nsec = 1; nsec <= MAXSLEEP; nsec <<= 1) { if (connect(sockfd, addr, alen) == 0) { /* * Connection accepted. */ return(0); } /* * Delay before trying again. */ if (nsec <= MAXSLEEP/2) sleep(nsec); } return(-1); } |
listen():
NAME
listen() – listen for connections on a socket
SYNOPSIS
#include <sys/socket.h> int listen(int sockfd, int backlog); |
So if you’re going to be listening for incoming connections, the sequence of system calls you’ll make is something like this:
socket();
bind();
listen();
/* accept() goes here */
Arguments:
An example code snippet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | struct hostent *he; struct sockaddr_in server; int sockfd; /* resolve localhost to an IP (should be 127.0.0.1) */ if ((he = gethostbyname("localhost")) == NULL) { puts("error resolving hostname.."); exit(1); } /* * copy the network address part of the structure to the * sockaddr_in structure which is passed to connect() */ memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length); server.sin_family = AF_INET; server.sin_port = htons(7000); /* connect */ if (connect(sockfd, (struct sockaddr *)&server, sizeof(server)) { puts("error connecting.."); exit(1); } |
accept():
NAME
accept() – accept a connection on a socket
SYNOPSIS
1 2 3 | #include <sys/types.h> #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, int *addrlen); |
Arguments:
The following is a program example that demonstrates the use of the previous functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> /* the port users will be connecting to */ #define MYPORT 3440 /* how many pending connections queue will hold */ #define BACKLOG 10 int main( void ) { /* listen on sock_fd, new connection on new_fd */ int sockfd, new_fd; /* my address information, address where I run this program */ struct sockaddr_in my_addr; /* remote address information */ struct sockaddr_in their_addr; int sin_size; // Create a socket: sockfd = socket( AF_INET, SOCK_STREAM, 0 ); if( sockfd == -1 ) { perror( "socket() error!" ); exit( 1 ); } else { printf( "socket() is OK...\n" ); } /* host byte order */ my_addr.sin_family = AF_INET; /* short, network byte order */ my_addr.sin_port = htons(MYPORT); /* auto-fill with my IP */ my_addr.sin_addr.s_addr = INADDR_ANY; /* zero the rest of the struct */ memset( &(my_addr.sin_zero), 0, sizeof my_addr.sin_zero ); //Bind socket to my address if( bind( sockfd, ( struct sockaddr * )&my_addr, sizeof( struct sockaddr )) == -1 ) { perror("bind() error!"); exit(1); } else { printf("bind() is OK...\n"); } if( listen( sockfd, BACKLOG ) == -1 ) { perror("listen() error lol!"); exit(1); } else { printf("listen() is OK...\n"); } /* ...other codes to read the received data... */ sin_size = sizeof(struct sockaddr_in); new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); if( new_fd == -1 ){ perror("accept() error lol!"); } else { printf("accept() is OK...\n"); } /*.....other codes.......*/ close(new_fd); close(sockfd); return 0; } |
send():
NAME – sends a message
SYNOPSIS:
#include <sys/socket.h> int send(int fd, const void *msg, int len, int flags); |
Arguments:
An example code snippet:
char *message="This is a message to send\n\r"; send(new_socket,message,strlen(message),0); |
recv():
NAME- recieve data from a connected socket.
SYNOPSIS:
#include <sys/socket.h> int recv(int fd, void *buf, int len, unsigned int flags); |
Arguments:
Like in the send() function, this function is used to send data over stream sockets or CONNECTED datagram sockets. If you want to send data over UNCONNECTED datagram sockets you must use recvfrom().
recv() returns the number of bytes read into the buffer and it’ll return -1 on error.
sendto():
NAME- Send data to a destination
SYNOPSIS:
int sendto(int fd,const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen); |
Arguments:
As you can see, sendto() is just like send(). It has only two more arguments : “to” and “tolen” . sendto() is used for UNCONNECTED datagram sockets and it returns the number of bytes sent out and it will return -1 on error.
recvfrom():
NAME – Recieve data from a destination
SYNOPSIS:
int recvfrom(int fd,void *buf, int len, unsigned int flags struct sockaddr *from, int *fromlen); |
Arguments:
recvfrom() returns the number of bytes received and it’ll return -1 on error.
close
NAME- Closes a connection
SYNOPSIS:
close(fd); |
close() is used to close the connection on your socket descriptor. If you call close(),it won’t be no more writes or reads and if someone tries to read/write will receive an error.
shutdown():
NAME- Shutdowns a socket
SYNOPSIS:
int shutdown(int fd, int how); |
Arguments:
When how is set to 2, it’s the same thing as close(). shutdown() returns 0 on success and -1 on error.
write()
NAME- write() – write to a file descriptor
SYNOPSIS
#include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); |
read()
NAME – read() – read from a file descriptor
SYNOPSIS
#include <unistd.h> ssize_t read(int fd, void *buf, size_t count); |
A Simple Client Application Flow
socket()
connect()
while (x)
{
write()
read()
}
close()
A Simple Server Application Flow
socket()
bind()
listen()
while (1)
{
accept()
while (x)
{
read()
write()
}
close()
}
close()
Iterative, Connection-Oriented Server Algorithm
create a socket
bind to a well-known port
place in passive mode
while (1)
{
Accept the next connection
while (client writes)
{
read a client request
perform requested action
send a reply
}
close the client socket
}
close the passive socket
Iterative, Connectionless Server Algorithm
create a socket
bind to a well-known port
while (1)
{
read a request from some client
send a reply to that client
}
recvfrom(s, buf, len, flags, from, fromlen)
sendto(s, buf, len, flags, to, to_len)
Iterative, Connectionless Server Algorithm
create a socket
bind to a well-known port
while (1)
{
read a request from some client
fork
if(child)
{
send a reply to that client
exit
}
}
Concurrent, Connection-Oriented Server Algorithm
create a socket
bind to a well-known port
use listen to place in passive mode
while (1)
{
accept a client connection
fork
if (child)
{
communicate with new socket
close new socket
exit
}
else
{close new socket}
}
Concurrency Using a Single Process
create a socket
bind to a well-known port
while (1)
{
use select to wait for I/O
if(original socket is ready)
{
accept() a new connection and add to read list
}
else if (a socket is ready for read)
{
read data from a client
if(data completes a request)
{
do the request
if(reply needed) add socket to write list
}
}
else if (a socket is ready for write)
{
write data to a client
if(message is complete)
{
remove socket from write list
}
else
{
adjust write parameters and leave in write list
}
}
}
When to Use the Various Server Types
Iterative server is simpler to write.
Concurrent server is faster.
Use iterative if it is fast enough.
Writing a single process concurrent server is harder.
Use a single process if data must be shared between clients.
Use multiple processes if each slave is isolated or if you have multiple CPUs.
Use connectionless if the protocol handles reliability.
Use connectionless on a LAN with no errors.
Avoiding Server Deadlock
Client connects but sends no request. Server blocks in read call.
Client sends request, but reads no replies. Server blocks in write call.
Concurrent servers with slaves are robust.
Libraries
<arpa/inet.h> |
Defines prototypes for those network library routines that convert Internet address and dotted-decimal notation, for example, inet_makeaddr().
<arpa/nameser.h> |
Defines Internet name server macros and structures that are needed when the system uses the resolver routines.
<error.h> |
Defines macros and variables for error reporting.
<fcntl.h> |
Defines prototypes, macros, variables, and structures for control-type functions, for example, fcntl().
<net/if.h> |
Defines prototypes, macros, variables, and the ifreq and ifconf structures that are associated with ioctl() requests that affect interfaces.
<net/route.h> |
Defines prototypes, macros, variables, and the rtentry and rtconf structures that are associated with ioctl() requests that affect routing entries.
<netdb.h> |
Contains data definitions for the network library routines. Defines the following structures:
hostent and hostent_data.
netent and netent_data.
servent and servent_data.
protoent and protoent_data.
<netinet/in.h> |
Defines prototypes, macros, variables, and the sockaddr_in structure to use with Internet domain sockets.
<netinet/ip.h> |
Defines macros, variables, and structures that are associated with setting IP options.
<netinet/ip_icmp.h> |
Defines macros, variables, and structures that are associated with the Internet Control Message Protocol (ICMP).
<netinet/tcp.h> |
Defines macros, variables, and structures that are associated with setting TCP options.
<netns/idp.h> |
Defines IPX packet header. May be needed in AF_NS socket applications.
<netns/ipx.h> |
Defines ioctl structures for IPX ioctl() requests. May be needed in AF_NS socket applications.
<netns/ns.h> |
Defines AF_NS socket structures and options. You must include this file in AF_NS socket applications.
<netns/sp.h> |
Defines SPX packet header. May be needed in AF_NS socket applications.
<nettel/tel.h> |
Defines sockaddr_tel structure and related structures and macros. You must include this file in AF_TELEPHONY socket applications.
<resolv.h> |
Contains macros and structures that are used by the resolver routines.
<ssl.h> |
Defines Secure Sockets Layer (SSL) prototypes, macros, variables, and the following structures:
SSLInit
SSLHandle
<sys/ioctl.h> |
Defines prototypes, macros, variables, and structures for I/O control-type functions, for example, ioctl().
<sys/param.h> |
Defines some limits to system fields, in addition to miscellaneous macros and prototypes.
<sys/signal.h> |
Defines additional macros, types, structures, and functions that are used by signal routines.
<sys/socket.h> |
Defines socket prototypes, macros, variables, and the following structures:
sockaddr
msghdr
linger
You must include this file in all socket applications.
<sys/time.h> |
Defines prototypes, macros, variables, and structures that are associated with time functions.
<sys/types.h> |
Defines various data types. Also includes prototypes, macros, variables, and structures that are associated with the select() function. You must include this file in all socket applications.
<sys/uio.h> |
Defines prototypes, macros, variables, and structures that are associated with I/O functions.
<sys/un.h> |
Defines prototypes, macros, variables, and the sockaddr_un structure to use with UNIX domain sockets.
<unistd.h> |
Contains macros and structures that are defined by the integrated file system. Needed when the system uses the read() and write() system functions.
An Example Application
The following example codes are from IBM developerwork’s article on nweb(a basic http server and client – see resource 9). You can compile the server code with the following command on linux:
gcc -g -ggdb -std=c99 -DLINUX -pedantic -Wall -O2 server.c -o server
To test the server after running :
telnet localhost 8181
Server’s source code, server.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <signal.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define BUFSIZE 8096 #define ERROR 42 #define SORRY 43 #define LOG 44 struct { char *ext; char *filetype; } extensions [] = { {"gif", "image/gif" }, {"jpg", "image/jpeg"}, {"jpeg","image/jpeg"}, {"png", "image/png" }, {"zip", "image/zip" }, {"gz", "image/gz" }, {"tar", "image/tar" }, {"htm", "text/html" }, {"html","text/html" }, {0,0} }; /* Pseudo code: log() { outputs error, sorry or log messages to the nweb.log file if a sorry message, transmit it to the browser as a fake HTML response if error or sorry message the program is stopped } */ void log(int type, char *s1, char *s2, int num) { int fd ; char logbuffer[BUFSIZE*2]; switch (type) { case ERROR: (void)sprintf(logbuffer,"ERROR: %s:%s Errno=%d exiting pid=%d",s1, s2, errno,getpid()); break; case SORRY: (void)sprintf(logbuffer, "<HTML><BODY><H1>nweb Web Server Sorry: %s %s</H1></BODY></HTML>\r\n", s1, s2); (void)write(num,logbuffer,strlen(logbuffer)); (void)sprintf(logbuffer,"SORRY: %s:%s",s1, s2); break; case LOG: (void)sprintf(logbuffer," INFO: %s:%s:%d",s1, s2,num); break; } /* no checks here, nothing can be done a failure anyway */ if((fd = open("nweb.log", O_CREAT| O_WRONLY | O_APPEND,0644)) >= 0) { (void)write(fd,logbuffer,strlen(logbuffer)); (void)write(fd,"\n",1); (void)close(fd); } if(type == ERROR || type == SORRY) exit(3); } /* Pseudo code: web() - this function returns the request back to the browser { read from the socket the HTTP request check it’s a simple GET command check no parent directory requested to escape the web servers home directory if no file name given assume index.html check the file extension is valid and supported check the file is readable by opening it transmit the HTTP header to the browser transmit the file contents to the browser if LINUX sleep for one second to ensure the data arrives at the browser stop } */ /* this is a child web server process, so we can exit on errors */ void web(int fd, int hit) { int j, file_fd, buflen, len; long i, ret; char * fstr; static char buffer[BUFSIZE+1]; /* static so zero filled */ ret =read(fd,buffer,BUFSIZE); /* read Web request in one go */ if(ret == 0 || ret == -1) { /* read failure stop now */ log(SORRY,"failed to read browser request","",fd); } if(ret > 0 && ret < BUFSIZE) /* return code is valid chars */ buffer[ret]=0; /* terminate the buffer */ else buffer[0]=0; for(i=0;i<ret;i++) /* remove CF and LF characters */ if(buffer[i] == '\r' || buffer[i] == '\n') buffer[i]='*'; log(LOG,"request",buffer,hit); if( strncmp(buffer,"GET ",4) && strncmp(buffer,"get ",4) ) log(SORRY,"Only simple GET operation supported",buffer,fd); for(i=4;i<BUFSIZE;i++) { /* null terminate after the second space to ignore extra stuff */ if(buffer[i] == ' ') { /* string is "GET URL " +lots of other stuff */ buffer[i] = 0; break; } } for(j=0;j<i-1;j++) /* check for illegal parent directory use .. */ if(buffer[j] == '.' && buffer[j+1] == '.') log(SORRY,"Parent directory (..) path names not supported",buffer,fd); if( !strncmp(&buffer[0],"GET /\0",6) || !strncmp(&buffer[0],"get /\0",6) ) /* convert no filename to index file */ (void)strcpy(buffer,"GET /index.html"); /* work out the file type and check we support it */ buflen=strlen(buffer); fstr = (char *)0; for(i=0;extensions[i].ext != 0;i++) { len = strlen(extensions[i].ext); if( !strncmp(&buffer[buflen-len], extensions[i].ext, len)) { fstr =extensions[i].filetype; break; } } if(fstr == 0) log(SORRY,"file extension type not supported",buffer,fd); if(( file_fd = open(&buffer[5],O_RDONLY)) == -1) /* open the file for reading */ log(SORRY, "failed to open file",&buffer[5],fd); log(LOG,"SEND",&buffer[5],hit); (void)sprintf(buffer,"HTTP/1.0 200 OK\r\nContent-Type: %s\r\n\r\n", fstr); (void)write(fd,buffer,strlen(buffer)); /* send file in 8KB block - last block may be smaller */ while ( (ret = read(file_fd, buffer, BUFSIZE)) > 0 ) { (void)write(fd,buffer,ret); } #ifdef LINUX sleep(1); /* to allow socket to drain */ #endif exit(1); } /* Pseudo code: main() { if option is "-?", output the hints and stop check the directory supplied is sensible and not a security risk become a daemon process ignore child programs (to avoid zombies when child processes stop) create a socket, bind it to a port number and start listening to the socket forever { wait and accept incoming socket connection fork a child process if the child process then call the web function else close new connection } } */ int main(int argc, char **argv) { int i, port, pid, listenfd, socketfd, hit; size_t length; static struct sockaddr_in cli_addr; /* static = initialised to zeros */ static struct sockaddr_in serv_addr; /* static = initialised to zeros */ if( argc < 3 || argc > 3 || !strcmp(argv[1], "-?") ) { (void)printf("hint: nweb Port-Number Top-Directory\n\n" "\tnweb is a small and very safe mini web server\n" "\tnweb only servers out file/web pages with extensions named below\n" "\t and only from the named directory or its sub-directories.\n" "\tThere is no fancy features = safe and secure.\n\n" "\tExample: nweb 8181 /home/nwebdir &\n\n" "\tOnly Supports:"); for(i=0;extensions[i].ext != 0;i++) (void)printf(" %s",extensions[i].ext); (void)printf("\n\tNot Supported: URLs including \"..\", Java, Javascript, CGI\n" "\tNot Supported: directories / /etc /bin /lib /tmp /usr /dev /sbin \n" "\tNo warranty given or implied\n\tNigel Griffiths nag@uk.ibm.com\n" ); exit(0); } if( !strncmp(argv[2],"/" ,2 ) || !strncmp(argv[2],"/etc", 5 ) || !strncmp(argv[2],"/bin",5 ) || !strncmp(argv[2],"/lib", 5 ) || !strncmp(argv[2],"/tmp",5 ) || !strncmp(argv[2],"/usr", 5 ) || !strncmp(argv[2],"/dev",5 ) || !strncmp(argv[2],"/sbin",6) ){ (void)printf("ERROR: Bad top directory %s, see nweb -?\n",argv[2]); exit(3); } if(chdir(argv[2]) == -1){ (void)printf("ERROR: Can't Change to directory %s\n",argv[2]); exit(4); } /* Become deamon + unstopable and no zombies children (= no wait()) */ if(fork() != 0) return 0; /* parent returns OK to shell */ (void)signal(SIGCLD, SIG_IGN); /* ignore child death */ (void)signal(SIGHUP, SIG_IGN); /* ignore terminal hangups */ for(i=0;i<32;i++) (void)close(i); /* close open files */ (void)setpgrp(); /* break away from process group */ log(LOG,"nweb starting",argv[1],getpid()); /* setup the network socket */ if((listenfd = socket(AF_INET, SOCK_STREAM,0)) <0) log(ERROR, "system call","socket",0); port = atoi(argv[1]); if(port < 0 || port >60000) log(ERROR,"Invalid port number (try 1->60000)",argv[1],0); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(port); if(bind(listenfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) <0) log(ERROR,"system call","bind",0); if( listen(listenfd,64) <0) log(ERROR,"system call","listen",0); for(hit=1; ;hit++) { length = sizeof(cli_addr); if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0) log(ERROR,"system call","accept",0); if((pid = fork()) < 0) { log(ERROR,"system call","fork",0); } else { if(pid == 0) { /* child */ (void)close(listenfd); web(socketfd,hit); /* never returns */ } else { /* parent */ (void)close(socketfd); } } } return 0; } |
Client’s source code, client.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 8181 /* port number as an integer */ #define IP_ADDRESS "9.137.62.23" /* IP address as a string */ #define BUFSIZE 8196 pexit(char * msg) { perror(msg); exit(1); } int main() { int i,sockfd; char buffer[BUFSIZE]; static struct sockaddr_in serv_addr; printf("client trying to connect to %s and port %d\n",IP_ADDRESS,PORT); if((sockfd = socket(AF_INET, SOCK_STREAM,0)) <0) pexit("socket() failed"); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = inet_addr(IP_ADDRESS); serv_addr.sin_port = htons(PORT); if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) <0) pexit("connect() failed"); /* now the sockfd can be used to communicate to the server */ write(sockfd, "GET /index.html \r\n", 18); /* note second space is a delimiter and important */ /* this displays the raw HTML file as received by the browser */ while( (i=read(sockfd,buffer,BUFSIZE)) > 0) write(1,buffer,i); return 0; } |
Resources
Oct 31st
Git is a very nice and useful distributed version control system. It certainly became a component for the swiss army knife of software engineers. Git is created by the father of Linux, Linus Torvalds. The main advantage of git over SVN and other traditional VCS’s(version control systems) is its distributed nature and performance(git is really fast and written mostly in C). Being distributed is important because all the users have the local copy and if one local copy is somehow deleted or damaged. Also it brings performance benefits. Reduces the load on a machine. You don’t have to do all your commits to the central repository. Others can recover. In this article I’m going to describe you about how to create a remote Git repository to connect with SSH and some basics related to git.
How to create Git Repository
Remote Repository
There are some initial steps to do before creating our repo, if you haven’t done yet. Of course at first you should install git. You can install with following commands:
For Ubuntu and Debian forks:
sudo apt-get install git
For FreeBSD and PCBSD(login with root user):
cd /usr/ports/devel/git && make install && make clean && cd -
After you’ve completed those steps you should now create a user. Let’s say we created a user called git:
adduser git
Now you have created a user and installed git. We can successfully create our repository now. To create our repo now login with the user you have created:
su git
Create a file called repos on your user’s home directory:
mkdir repos && cd repos
Now here comes the crucial parts. Create a directory called which has a relevant name for your project. At the moment we’re just testing so let’s name it test.git(general convention when creating a repo for git is the repo name ends with .git):
mkdir test.git && cd test.git
We’ll initialize our repository with some templates and skeletons for a git repository:
git --bare init
That’s all for remote git server.
Local Git Repository
You should also install git to your local machine too. Then you can do some configurations related with you local computer. For instance:To set you name:
git config --global user.name "Your Name Comes Here"
To set your email:
git config --global user.email you@yourdomain.example.com
To see all configuration settings:
git config --list
You should go to your project directory and initialize git:
cd ~user/Codes/test
git init
Create an example file called test:
touch TEST
Add files to your local git repository:
git add .
Commit to the local repository:
git commit -m "first commit"
Add the remote server’s address with ssh access:
git remote add origin ssh://git@server_address/path_to_repository/test.git
Now push the changes to the server:
git push origin master
The git push commands push the changes to the destination repository you’ve specified. In above we’ve push the changes at master(our repository that we are working on) to origin (remote repository). You should at first do changes in your local repository and after you have completed your changes, push those changes to the remote repository. Try to do your updates commits to local repository atomic. Commit all minor the changes you’ve done in the local repository. Congratulations, you have successfully created your local and remote repository.
Some Git Basics:
Ok we’ve created our repos now let’s check some basic commands.
git add : This command adds the current content of new or modified files to the index, thus staging that content for inclusion in the next commit. We can specifically give file names that’ll be added or with -A option we can add all commands. With -v option this command runs in verbose mode.
Example:
git add test.c
OR:
git add -v .
We should add all our newly created files with this command at first.
git commit:
Stores the current contents of the index in a new commit along with a log message from the user describing the changes. With -m option you can enter some additional comments and logs related to the update. -a option commits all changes.
Example:
git add hw.cpp
git commit hw.cpp -m "Patch added for the 64 bit CPUs."
OR:
git add .
git commit -a -v
git status: This command displays paths that have differences between the index file and the current HEAD commit, paths that have differences between the working tree and the index file, and paths in the working tree that are not tracked by git (and are not ignored by gitignore(5)). All the output lines are prefixed with #. Basically this command gives general information about changes done after the last commit.
Example:
git status
Sample Output:
# On branch master
# Changes to be committed:
# (use “git reset HEAD …” to unstage)
#
# modified: file1
# modified: file2
# modified: file3
#
git pull: Fetchs from and merge with another repository or a local branch and updates the local branch. –log option generates log messages. This command has a similar functionality of “svn update”.
Command format:
git pull
git push: Updates the remote repository by sending the necessary objects to the remote repository.
Command format:
git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=]
[--repo=] [-f | --force] [-v | --verbose]
[ ...]
Example:
git push origin master
git fetch: Download objects and refs from another repository. This command doesn’t have merge functionality like pull.
Command format:
git fetch ..
Example:
git fetch origin [branchname]
git diff: Shows changes between commits, commit and working tree, etc.
Command format:
git diff [] {0,2} [--] [
...]
Common usages:
You will commonly use git diff for figuring out differences between your last commit, your index, and your current working directory. A common use is to simply run
git diff
which will show you changes in the working directory that are not yet staged for the next commit. If you want to see what is staged for the next commit, you can run
git diff --cached
which will show you the difference between the index and your last commit; what you would be committing if you run "git commit" without the "-a" option. Lastly, you can run
git diff HEAD
which shows changes in the working directory since your last commit; what you would be committing if you run "git commit -a".Detailed info related to "git diff" command
git log : This command shows commit logs.
Example Usages:
At any point you can view the history of your changes using
git log
If you also want to see complete diffs at each step, use
git log -p
Often the overview of the change is useful to get a feel of each step
git log --stat --summary
Stashing
Let's say that you are working in a git tree and have previously made some local commits. Then you started working on other code and modified several other files. However, you then decide to push the previously made commits to the central repository (e.g. those commits fix a critical bug). However, git will not let you push your commits because your tree is not clean.
In the absence of originally using a branch to do the newer hacking, you can easily create a temporary branch, move the work-in-progress to the temporary branch, push your commits to the server, and then re-apply your work-in-progress to the current branch. Git has a wonderful built-in command that will do all this work for you: stash. To stash all work-in-progress on the current tree, use:
git stash
When you need to pull the changes back, use:
git stash apply
For more detailed tutorial about git run the following command:
man gittutorial
For a description related to a specific git command, run this command:
man git-action_name
For example:
man git-fetch
Jul 6th
Semiotic Dynamics
Semiotics is basically study of signs but not in the sense of visual signs like traffic signs. But in more general sense, body language , sounds , words and any kind of communicative or informative units can be a sign. Semiotic Dynamics, is dynamics of communicative signs among the population of agents and it studies how populations of humans or agents can establish and share semiotic systems, typically driven by their use in communication.
Semiotic dynamic is built on many earlier AI topics like , the understandings and concepts of semantic networks and knowledge representations from the seventies, the ideas on embodiment and grounding from the late eighties and the perspective of multiagent systems from the nineties. But all those concepts join together into a new vision of intelligence , with social , collective dynamics of representation-making at the core. Those AI developments don’t stand in isolation of computer science perspective. They collaborate with recent developments in cognitive science where the research focus is rapidly shifting from looking only at the (static) competence of an “idealized speaker” toward the notion that language is a complex adaptive system, continuously changing and adapting to accommodate its users’ needs in social interaction. They also rest on recent developments of mathematics on networks and graph theory(specifically bigraphs), which have enhanced our understanding in the behaviour of numerous complex systems, from stock markets to ecologies to the Internet.
Language as a complex adaptive system
In the late eighties and early nineties, psycholinguists started looking in detail at situated human dialogue and came to a startling conclusion. Dialogue partners quickly and continuously adapt to each other at all levels of language: phonetic, lexical, syntactic, grammatical, conceptual, and pragmatic. Of course, they come to the conversation with partly established systems, but these aren’t fixed systems; they’re adapted, expanded, and negotiated to serve the ongoing dialogue—often based on repairing miscommunication—to optimize communicative success and minimize cognitive effort. According to semiotics dynamics such change might involve,
• inventing new words or stretching usage,
• adopting a grammatical construction for a slightly new purpose,
• introducing new concepts or shifts in how concepts are perceptually grounded in sensorimotor experience,
• aligning dialogue partners’ speech sounds and intonation patterns, and
• coordinating turn-taking behaviour and gestures.
The naming game
The naming game is played by a population of agents—having the same sort of cognitive mechanisms but each with its own local memory. There’s no central control or prior vocabulary of names. In each game, two random players are chosen from the population. The speaker picks an object from the current context, searches his memory for a name for this object, and tells the hearer. The hearer then points to the object that she associates with this name. The game is a success if the hearer correctly identifies the object that the speaker originally chose. Otherwise, it’s a failure and the speaker points to the object he intended.
Baronchelli etal used the following strategy in order to model the semiotic dynamics:
The Naming Game is played by a population of M agents those are trying to accomplish to have a common vocabulary for a certain number K of individual objects that are presented in their environment, so that one agent can draw the attention of another one to an object, e.g. to obtain it or converse further about it. The objects can be people, physical objects, relations, web sites, pictures, music files, or any other kind of entity for which a population aims at reaching a consensus as far as their naming is concerned. Each player is characterized by his inventory, i.e. the word-object pairs he knows. All the agents have empty inventories at time t = 0. At each time step (t = 1, 2, ..) two players are picked at random and one of them plays as speaker and the other as hearer. Their interaction obeys the following rules (see Fig. 1):

Fig1: Inventory Dynamics (Baronchelli etal)
Step 1: The speaker selects an object from the current context;
Step 2: The speaker retrieves a word from its inventory associated with the chosen object,
or, if its inventory is empty, invents a new word;
Step 3: The speaker transmits the selected word to the hearer;
Step 4: If the hearer has the word named by the speaker in its inventory and that word
is associated to the object chosen by the speaker, the interaction is a success and
both players maintain in their inventories only the winning word, deleting all the
others;(Interaction is successful)
Step 5: If the hearer does not have the word named by the speaker in its inventory, the
interaction is a failure and the hearer updates its inventory by adding an association
between the new word and the object.(Interaction is failure)
At the end of the game all agents’ inventory converge to the same word-object pair.
Baronchelli etal also to speed up the convergence developed the smart strategy which basically composed of 2 steps:
Rule 1: If the speaker has never took part in a successful game, he plays the last word recorded;
Rule 2: Else, if the speaker has won at least once, he plays the last word he had a communicative success with.
They also developed mathematical models based on this strategy.
There are many other strategies exist for this sort of game. For example, agents could use a neural network-like associative memory for storing weighted associations between objects and names (ignoring the issues of object recognition and speech production or perception) and increase or decrease the weights on the basis of success or failure in the game. However, any strategy chosen must have two basic ingredients: alignment and innovation.
After every game, the speaker and hearer should align or adjust their associative memories to make their vocabularies more similar. For example, suppose they used weighted networks. If the game is a success, they should increase the weight of the used association so that it’s used even more in the future and decrease the weight of competing associations (other names for the same object). If the game is a failure, the agents know that they don’t share each other’s associations, so they should diminish their respective weights.
In addition to alignment, we need innovation— otherwise, the system could never move forward. Innovation here means that a speaker who doesn’t have a name for an object could invent one and add it to her memory. If the hearer doesn’t know a name, he can adopt it by storing it in his memory with some initial weight.
A strategy based on these two ingredients quickly leads a group of agents to a set of shared naming conventions without global control or prior design (see figure 1). Researchers have also studied this game using a more classical iterated-transmission approach, both genetically10 and culturally, but the model I discuss here relies entirely on self-organization due to the positive-feedback loop between use and success. Agents don’t need to go through many generations before reaching a consensus, so convergence appears surprisingly fast. Moreover, the system remains adaptive: When new objects appear, agents invent names for them, which then spread throughout the population. When new agents enter the population, they might this dynamic lets a population self-organize a shared lexicon as well as the underlying perceptually grounded ontology.
Complex systems theory
Although we know from computer simulations that a population of embodied agents can self-organize a semiotic system, we’ve only recently understood why this was or how to predict these systems’ properties, such as convergence time, scaling laws, limits in population or object in- and outflow, resistance to noise in transmission or pointing, and so on. It turns out that we needed a set of mathematical tools developed recently as part of advances in graph theory triggered by the study of complex networks and their application to a wide range of complex dynamical systems.

Fig2: Scaling the population size N (Baronchelli etal)
Andrea Baronchelli, Vittorio Loreto, and their colleagues recently discovered how to apply these techniques to semiotic dynamics.They studied a simplified naming-game strategy (a more discrete version of the weighted updating discussed earlier) and population scaling. They discovered that theconvergence times (tconv), which generally follow an S-shaped curve typical in studies of language change) scale following a power law (see figure 3). Building on this, we might ask how we can explain this power law’s exponent and use this to understand the naming game’s collective dynamics. Here, we can learn from complex-systems science. We can aggregate the various quantities involved (for example, the number of words known by the population’s agents for an object) and develop master equations regulating them. Adopting the mean-field assumption common in statistical mechanics, we can then predict the system’s general behavior, including the power law’s exponents.
Possible Applications
There are many possible application domains of semiotic dynamics. Some of them are as following:
1)Collobarative Tagging
Collaborative tagging is process of the enriching web contents with semantically meaningful information in the form of freely chosen text labels (tags) that are managed, shared and browsed by web users. Typical examples are del.icio.us, Flickr, CiteULike and Connetea.

Schematic representation of Collaborative Tagging
Ciro Cattuta etal (2006) gathared tags and categories related to those tags and created the cooccurence rank table and with the findings they have established , they tried to predict and control the Semiotic Dynamics of online communities.
2)Collective Learning
In Luc Steels etal (1999) did the Talking Heads experiment in order to show the relation between the collective learning and semiotic dynamics:
In the talking heads experiment there are several robots which are actually composed of a monitor, a camera and a computer for cognitive processing(perception, categorization, lexicon lookup, etc. ), a screen on which the internal states of the agent currently loaded in the body are shown, a TV-monitor showing the scene as seen through the camera, and devices for audio in- and output. Agents can load themselves in a physical Talking Head and teleport themselves to another Head by using Internet. An agent can only interact with another one when it is instantiated in a body located in a shared physical environment. Agents are capable of segmenting the image perceived through the camera into objects and of collecting various sensory data about object. A set of object is shown to one robot. Those objects and their data constitute a context. Speaker chooses one object from this context which is called topic and the other agent(hearer) forms the background. The speaker gives a verbal hint to the hearer.
The verbal hint is an utterance that identifies the topic with respect to the objects in the background like red square, blue circle etc… Talking heads don’t say read square but rather they invent their own words like malewina to mean [UPPER EXTREME - LEFT LOW-REDNESS]. The hearer tries to guess the topic that speaker chosen by pointing the object according to the the verbal hint. The game is successful if the topic guessed by the hearer is equal to the topicchosen by the speaker. Otherwise the game fails.
References
1. Ciro Cattuto , Vittorio Loreto and Luciano Pietronero , Collaborative Tagging and Semiotic Dynamics , 2006.
2. Luc Steels, Frederic Kaplan , Collective learning and semiotic dynamics, 1999.
3. Vogt, P., Coumans, H.: Investigating social interaction strategies for bootstrapping lexicon development. Journal of Artificial Societies and Social Simulation 6(1) (2003) http://jasss.soc.surrey.ac.uk/6/1/4.html .
4. Smith, A.D.M.: Intelligent meaning creation in a clumpy world helps communication. Artificial Life 9(2) (2003) 175–190.
5. Steels, Luc, Loetzsch, Martin, and Spranger, Michael. Semiotic Dynamics Solves the Symbol Grounding Problem. Available from Nature Precedings.
6. Semiotic Dynamics for Embodied Agents , Luc Steels , IEEE Intelligent Systems , 2006.
7.Andrea Baronchelli, Luca Dall’Asta, Alain Barrat and Vittorio Loreto , Strategies for fast convergence in semiotic dynamics , 2005.
8.Sharp transition towards shared vocabularies in multi-agent systems, Andrea Baronchelli, Maddalena Felici and Vittorio Loreto, 2006.
Jun 23rd
Distributed Cognition
Distributed cognition is a psychological theory which is developed during the mid 1980s by Edwin Hutchins. Distributed cognition uses the different views from sociology, cognitive science, and the psychology. It basically emphasizes the social aspects of cognition. It is a framework rather than a method which involves the co-ordination between individuals and artifacts. It has two important components:
(i) the representations which information is held in and transformed across
(ii) the process by which representations are coordinated with each other. [3]
Distributed cognition is a topic in cognitive science which proposes that cognition and human knowledge is not limited to the individual. Instead, it is spread around our environment by placing memories, facts, knowledge about objects, people and tools in our surrounding. Social cues of cognition is ubiquitous and can be met in every man made object. Distributed cognition views a system as a set of representations, and models the interchange of information between these representations. According to distributed cognition all systems are a set of representations and distributed cognition models the exchange of information between those representations. Those representations can be in either in the mental space of individual or external representations available in the environment.
This abstraction can be categorized into three different types of processes:
1. Cognitive processes may be distributed across the members of a social group.
2. Cognitive processes may be distributed in the sense that the operation of the cognitive system involves coordination between internal and external (material or environmental) structure.
3. Processes may be distributed through time in such a way that the products of earlier events can transform the nature of related events.
Related Works
J. Roberts (1964) thought that social organization could be seen as cognition through a community. He described the cognitive aspects of a society by looking at the present information and how it moves through the people in the society.
Daniel L. Schwartz (1978) proposed a distribution of cognition through culture and the distribution of beliefs across the members of a society.
Early work in distributed cognition was motivated by the basic insight that cognition is a socially (also, materially and temporally) distributed phenomenon, one that is essentially situated in real practices (Hutchins 1995a). The theory does not posit some new kind of cognitive process. Rather, it represents the claim that cognitive processes generally are best understood as situated in and distributed across concrete socio-technical contexts.
The traditional sort of theory in cognitive science emphasizes an internalism that marginalizes (some would argue ignores) the role of external representation and problem solving in cooperative contexts. Traditional approaches to description and design in human-computer interaction have similarly focused on users internal models of the technologies with which they interact.
Alternative theoretical perspectives have since offered criticisms of the tradition, emphasizing instead the role of concrete social and technological contexts. An ecological approach emphasizes the role of agent-environment interaction. The role of socio-cultural context in mediating intentional action is emphasized by an approach called activity theory. And situated action theorists stress how attention to the concrete details of intelligent action reveals the shortcomings of abstract theoretical construals of human-machine interaction.
The theory of distributed cognition offers this same sort of critique of the tradition but does so in a way that does not reject traditional computationalist wisdom. In modern complex cooperative work environments, we find humans and technologies together maintaining and manipulating representational states, carrying out processes that solve problems. The theory of distributed cognition is motivated by the idea that such systems instantiate genuinely cognitive processes and that the cognitive properties of these types of socially, materially and temporally distributed systems differ from those of the individuals that act in them.
In 1999, Gavriel Salomon stated that there were two classes of distributive cognition: shared cognition and off-loading. Shared cognition is that which is shared among people through common activity such as conversation where there is a constant change of cognition based on the other person’s responses. An example of off-loading would be using a calculator to do arithmetic or a creating a grocery list when going shopping. In that sense, the cognitive duties are off-loaded to a material object.
Most recently, the theory od distributed cognition has been proposed as a “new foundation” for human-computer interaction (Hollan, et. al. 2000).
Explanation
The fundemental idea of distributed cognition is that the cognitive phenomenas are generally can be understood as distributed processes. Those processes in turn are cognitive in the traditional sense. Thus they are also computational processes. The theory doesn’t fully regret individual cognition, but rather the early works focused on studying instances of socio-culturally distributed cognition.The theoretical issue here is on how cognition is distributed across people and artifacts, and on how it depends on both internal and external representations.
Computation
The fundamental idea of cognitive science that cognition is computational process is also preserved in the theory of distributed cognition. However, computation is conceived broadly as “the propagation of representational state across representational media” (Hutchins 1995a). In a socially distributed system, people interact with artifacts to create and coordinate representations. So, representational state can be “propagated” across distinct media and across different representational systems.Therefore the computational complexity of a system is directly related with the amount of representational systems.
Unit of analysis
Traditional cognitive theory takes the individual person as the proper unit of analysis and on this traditional view, cognitive processes are internal processes. Thus the social and cultural context is thus often left out of the analysis. In contrast, the theory of distributed cognition makes use of the individual and its socio-cultural context a larger cognitive system, one that is to be analyzed in a broadly traditional way, as a computational system.
Enlarging the unit of analysis by taking socio cultural context into account has the benefit that representations internal to the system are now “external” representations with respect to the individual agents that use and make use of them. Therefore, cognitive processes are, from this theoretical standpoint, fully observable.
Using the notion of a variable unit of analysis, we can decompose larger cognitive systems into subsystems which can also be similarly decomposed. The unit of analysis is defined computationally (i.e. functionally). Nothing in the theory of distributed cognition prevents us from taking the individual as the unit of analysis.
Methodology
There are several methods for collecting empirical data that may be employed in a distributed cognition analysis. These include close study of video or audio recordings of work situations and computer (neural network) simulations. For research in the area of socially distributed systems, an especially important method is a new kind of cognitive enthographic study.
Metaphors and examples
Distributed cognition can be observed when using paper and pencil to do a complicated mathematical problem. The individual doing the problem might consult to her friend to clarify the problem and then must write the partial answers to the paper in order to keep track of every step in the solution. In this example we saw the following parts of distributed cognition:
* setting up the problem, in collaboration with another person,
* performing manipulation/mathematical procedures, both in one’s head and by writing down resulting partial answers.
The process of working out the answer not only limited to the perception and thought of two individuals but it also requires the use of a tool (paper) to extend an individual’s memory. So the intelligence is distributed, both between people, and a person and an object.
Another metaphor for distributed cognition would be a power plant and the staff working there. It is not the cognitive performance and expertise of any one single person or machine that is important for our well being. It is the cognition that is distributed over the engineers, sensors, and machinery both in the power plant and on the natural resources that power plant uses in order to produce electrical energy, including but not limited to the engineers and workers as a whole.
References
1. Distributed Cognition , <http://www.slis.indiana.edu/faculty/yrogers/dist_cog/>, Last Access: 07/06/2009 .
2. Distributed Cognition , <http://www.learning-theories.com/distributed-cognition-dcog.html> , Last Access: 07/06/2009.
3. Wikipedia Free Encylopedia, Distributed Cognition ,<http://en.wikipedia.org/wiki/Distributed_cognition>, Last Access: 07/06/2009 .
Jun 23rd
Mark Weiser is the person who firstly pointed out the term of ubiquitous computing(also sometimes recalled as calm technology).His thoughts were summarized in a brief burst simply entitled “Ubiquitous Computing” In it, as in the series of seminal papers and articles that followed, Weiser developed the idea of an “invisible” computing, a computing that “does not live on a personal device of any sort, but is in the woodwork everywhere.”
What Weiser was describing would be nothing less than computing without computers. In his telling, desktop machines per se would largely disappear, as the tiny, cheap microprocessors that powered them faded into the built environment. But computation would flourish, becoming intimately intertwined with the stuff of everyday life.
In this context, “ubiquitous” meant not merely “in every place,” but also “in every thing.” Ordinary objects, from coffee cups to raincoats to the paint on the walls, would be reconsidered as sites for the sensing and processing of information, and would wind up endowed with surprising new properties. Best of all, people would interact with these systems fluently and naturally, barely noticing the powerful informatics they were engaging. The innumerable hassles presented by personal computing would fade into history.
At the MIT Media Lab, Professor Hiroshi Ishii’s “Things That Think” initiative developed interfaces bridging the realms of bits and atoms, a “tangible media” extending computation out into the walls and doorways of everyday experience. At IBM, a whole research group grew up around a “pervasive computing” of smart objects, embedded sensors, and the always-on networks that connected them.
And as mobile phones began to percolate into the world, each of them nothing but a connected computing device, it was inevitable that someone would think to use them as a platform for the delivery of services beyond conversation. Philips and Samsung, Nokia and NTT DoCoMoall offered visions of a mobile, interconnected computing in which, naturally, their products took center stage.
By the first years of the twenty-first century, with daily reality sometimes threatening to leapfrog even the more imaginative theorists of ubicomp, it was clear that all of these endeavors were pointing at something becoming real in the world.
Intriguingly, though, and maybe a little infuriatingly, none of these institutions understood the problem domain in quite the same way. In their attempts to grapple with the implications of computing in the post-PC era, some concerned themselves with ubiquitous networking: the effort to extend network access to just about anyplace people could think of to go. With available Internet addresses dwindling by the day, this required the development of a new-generation Internet protocol.
One of the earliest ubiquitous systems was artist Natalie Jeremijenko’s “Live Wire”, also known as “Dangling String,” installed at Xerox PARC during Mark Weiser’s time there. This was a piece of string attached to a stepper motor and controlled by a LAN connection; network activity caused the string to twitch, yielding a peripherally noticeable indication of traffic. Weiser called this an example of calm technology.
Ambient Devices has produced an “orb”, a “dashboard”, and a “weather beacon”: these decorative devices receive data from a wireless network and report current events, such as stock prices and the weather, like the Nabaztag produced by Violet.
As seen from the examples ubiquitous computing and HCI are very closely related paradigms.
References
1. Adam Greenfield, Everyware: The dawning age of ubiquitous computing , 2006.
2. http://en.wikipedia.org/wiki/Ubiquitous_computing
Jun 7th
Hungarian mathematician George Polya’s Polya Processes are usually very helpful in problem-solving. Most of the students learn about it in secondary school or high school in math classes for problem solving but they are also useful for complex problems too:
May 31st
Richard Feynman was one of the most influential physist at the post-war era. He was also known as reducing the science to the ordinary men’s and masses level. He also break the taboo of crazy evil nerdy scientist taboo in US with his social and funny character.
In the following link, you can watch the documentary of Richard Feynman about his views on life and adventures about a small country called Tuva (Spoiler: I’m an explorer okay, I get curious about everything and I want to investigate all kinds of stuff. ) :
May 19th
Java hashtable’s are really easy to use and useful for many case . But for starters iterating in a hash table and getting the key of a value in a hash table might look mysterious. So I decided to put here a code which I hope may help :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | /** * * @author caglar */ import java.util.Collection; import java.util.Enumeration; import java.util.Hashtable; public class Main { /* * @param Hashtable hashtbl * This function prints the values in a hashtable in reverse order * The aim of this function is to show how to iterate over a hastable with values */ public static void printValues( Hashtable hashtbl ) { Collection coll = hashtbl.values(); Object objects[] = coll.toArray(); for ( Object object : objects ) { System.out.println( object ); } } /* * @param Hashtable hashtbl * This function prints the key value pair in a hashtable in reverse order * The aim of this function is to show how to iterate over a hastable with keys */ public static void printHashTable(Hashtable hashtbl) { Enumeration keys = hashtbl.keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); System.out.println(" Key :" + key + " Value: " + hashtbl.get(key)); } } /** * @param Hashtable hashtbl * @param Object value , value that we are looking for the key for * @return Object result, the key that we want to get * This function returns the key of a value in a hashtable */ public static Object getKeyOfValue(Hashtable hashtbl, Object value) { Enumeration keys = hashtbl.keys(); Object result = ""; while (keys.hasMoreElements()) { Object key = keys.nextElement(); Object valueOfKey = hashtbl.get(key); if (value.equals(valueOfKey)) { result = key; } } return result; } public static void main(String[] args) { Hashtable hashtbl = new Hashtable(); hashtbl.put("key1", "value1"); hashtbl.put("key2", "value2"); hashtbl.put("key3", "value3"); String keyValue = (String) getKeyOfValue(hashtbl, "value1"); System.out.println(keyValue); printHashTable(hashtbl); printValues(hashtbl); } } |
May 2nd
Infinite regress, is a very interesting and fun to play with kind of a topic. Let’s look at the Wikipedia definition of infinite regress:
An infinite regress in a series of propositions arises if the truth of proposition P1 requires the support of proposition P2, and for any proposition in the series Pn, the truth of Pn requires the support of the truth of Pn+1. There would never be adequate support for P1, because the infinite sequence needed to provide such support could not be completed.
To concretize the above definition, now consider the following propositional attitude:
S1) “S believes that T.”
Whereas S is a proper name and T is another propositional attitude.
S2) “S believes that A believes that K.”
Whereas A is a proper name and K is another propositional attitude.
S3) “S believes that A believes that X believes that A.”
Whereas X is a proper name and K is another propositional attitude.
.
.
.
And in this way we can hold out our sentence infinitely. Sn is an extension of Sn-1 and Sn-1 is an extension of Sn-2…etc.
Another interesting place where we meet infinite regress is in Homunculus Argument:
Homunculus argument was proposed for fallacy arising in most commonly vision. It can be explained like that, let’s consider that you have a homunculus in your head and he watches the images of the outside world that comes from your retina trough the nerve cells on a cinema screen. You ask the homunculus how he sees the images and then he answers that he has a homunculus in his head and that homunculus has another homunculus in his head and that homunculus has also a homunculus in his head and it goes like that. Here the infinite regress appears. The problem in here is that we are trying to account for a phenomenon in terms of the very phenomenon that it is supposed to explain. In a short sentence, the homunculus argument is trying to say that if there is a need for a ‘little man’ to complete a theory then the theory is false or incomplete.
Another common ground that we can deal with infinite regress is in mathematics especially in infinite sets. For instance Hilbert’s Grand Hotel paradox:
Let’s consider that there is a hypothetical hotel with infinite number of rooms and one day a new guest comes to hotel and ask to the receptionist if there is an empty room for him. Receptionist tells to the guest that there is no empty room in the hotel. Guest asks to receptionist if the guest at room 1 can move to the room 2 and guest at room 2 move to the room 3 etc… The receptionist accepts the guest’s offer and the rooms are changed. The next day infinite number of customers come to the hotel and ask for room. When they hear that there is no empty room, one of them come up with an idea, If all the guests staying in the hotel can move to the odd numbered rooms. All the even numbered rooms would be empty and so there will be a space for them.
So have fun with your own infinite regressions
.
Recent Comments