Main socket function calls
- Allocate a socket descriptor: Note: socket function call
int socket(int domain, int type, int protocol); ⋮ int server_sock; ⋮ server_sock = socket(AF_INET, SOCK_STREAM, 0);The previous example allocates socket descriptor server_sock in the internet addressing family, AF_INET, using a socket stream type and the default protocol TCP indicated by 0.
- You can bind an address to a socket in two ways:
- Explicitly bind a unique address to the socket: Note: bind function call
int bind(int s, struct sockaddr *name, int namelen); ⋮ int rc; int server_sock; struct sockaddr_in myname; ⋮ memset(&myname, 0, sizeof(myname)); myname.sin_family = AF_INET; myname.sin_port = 5001; myname.sin_addr.s_addr = inet_addr("129.5.24.1"); ⋮ rc = bind(server_sock, (struct sockaddr *) &myname, sizeof(myname));The previous example binds socket server_sock to internet address 129.5.24.1 and port 5001.
In this example, the network address and the port address were in the network byte order:- inet_addr was used to convert a character internet address to network byte order.
See each of these functions in the alphabetic reference section of z/TPF C/C++ Language Support User's Guide.
- Bind an address to the socket using a wild card: Note: bind function call
int bind(int s, struct * *name, int namelen); ⋮ int rc; int server_sock; struct *_in myname; ⋮ memset(&myname, 0, sizeof(myname)); myname.sin_family = AF_INET; myname.sin_port = 5001; myname.sin_addr.s_addr = INADDR_ANY; /* all interfaces */ rc = bind(s, (struct sockaddr *) &myname, sizeof(myname));
- Explicitly bind a unique address to the socket:
- The server indicates its readiness to accept connections from
clients: Note: listen function call
int listen(int s, int backlog); ⋮ int rc; int server_sock; ⋮ rc = listen(server_sock, 5);This example indicates that the server is ready to accept calls, and that a maximum of 5 connect requests can be queued for the server. Additional requests are ignored.
- The client starts a connection request: Note: connect function call
int connect(int s, struct sockaddr *name, int namelen); ⋮ int rc; int client_sock; struct sockaddr_in servername; ⋮ memset(&servername, 0, sizeof(servername)); servername.sin_family = AF_INET; servername.sin_port = 5001; servername.sin_addr.s_addr = inet_addr("129.5.24.1"); ⋮ rc = connect(server_sock, (struct socaddr *) &servername, sizeof(servername));This example connects socket client_sock to the server with an address servername. This is the same server that was shown in the previous bind. The client could optionally be blocked until the connection is accepted by the server. On a successful return, socket server_sock is associated with the connection to the server.
- The server accepts the client's connection request: Note: accept function call
int accept(int s, struct sockaddr *addr, int *addrlen); ⋮ int addrlen; int newclient_sock; int server_sock; struct sockaddr client_addr; ⋮ addrlen = sizeof(client_addr); newclient_sock = accept(server_sock, &client_addr, &addrlen);When the server accepts a connection request on socket server_sock, the name of the client and the length of the client name are returned, along with a new socket descriptor. The new socket descriptor is associated with the client that began the connection, and server_sock is available to accept new connections.
- The client and server transmit data in the connected state: Note: send and recv function calls
int send(int s, char *msg, int len int flags); int recv(int s, char *msg, int len, int flags); ⋮ int client_sock; int bytes_sent; int bytes_recv; char data_sent[256]; char data_recv[256]; ⋮ bytes_sent = send(client_sock, data_sent, sizeof(data_sent), 0); ⋮ bytes_recv = recv(client_sock, data_recv, sizeof(data_recv), 0);The previous example shows an application sending data on a connected socket and receiving data in response. The flag fields can be used to specify additional options for send or recv.
Clients and servers can use many function calls to transfer data, such as:- The read, write, writev, send, and recv calls. However, these function calls can be used only on sockets in the connected state.
- The sendto and recvfrom function calls can be used in the unconnected state.
- The client and server transmit data when they are in the connectionless
state: Note: sendto and recvfrom function calls
int sendto(int socket, char *buf, int buflen, int flags; struct sockaddr *addr, int addrlen); int recvfrom(int socket, char *buf, int buflen, int flags; struct sockaddr *addr, int addrlen); ⋮ int addrlen; int client_sock; int bytes_sent; int bytes_recv; char data_send[256]; char data_recv[256]; struct sockaddr_in from_addr; struct sockaddr_in to_addr; ⋮ addrlen = sizeof(struct sockaddr_in); memset(&to_addr, 0, addrlen); to_addr.sin_family = AF_INET; to_addr.sin_port = 5001; to_addr.sin_addr.s_addr = inet_addr("129.5.24.1"); ⋮ bytes_sent = sendto(client_sock, data_sent, sizeof(data_sent), 0, (struct sockaddr *)&to_addr, addrlen); ⋮ bytes_recv = recvfrom(client_sock, data_recv, sizeof(data_recv), 0,(struct sockaddr *)&from_addr, &addrlen);If the socket is not connected, additional socket address information must be passed to sendto and can be optionally returned from recvfrom. The caller must specify the recipient of the data or to be notified of the sender of the data.
Usually, sendto and recvfrom are used for datagram sockets; read, send, and recv are used for stream sockets.
- Client and server can receive data using a special z/TPF function call
called activate_on_receipt: Note: activate_on_receipt function call issued from ECB 1
int accept(int s, struct sockaddr *addr, int *addrlen); int activate_on_receipt(unsigned int s, unsigned char *parm, unsigned char *pgm); ⋮ int addrlen; int newclient_sock; int server_sock; char aorparm[8]; char aorpgm[4] = "abcd"; ⋮ newclient = accept(server_sock, (struct sockaddr *)0, (int *)0); ⋮ /* No parameters will be passed to the new ECB */ memset(aorparm,0,sizeof(aorparm)); rc = activate_on_receipt(newclient, aorparm, aorpgm);The activate_on_receipt function call allows the issuing ECB to exit and activates a different ECB at program abcd. After the information has been received, the activated program, called the child server program, must issue a read, recv, or recvfrom function call to receive the information. See z/TPF C/C++ Language Support User's Guide for more information.
Note: read function call issued from ECB 2: abcd() { ⋮ int bytes_recv; int newclient_sock; int msg_length; char *read_addr; ⋮ /* socket descriptor, buffer address, and message */ /* length are returned in ECB */ newclient_sock = (int)ecbptr()->ebrout; memcpy(&read_addr,&(ecbptr()->ebw024),sizeof(read_addr)); memcpy(&msg_length,&(ecbptr()->ebw016),sizeof(msg_length)); bytes_recv = read(newclient_sock,read_addr,msg_length); ⋮ } - Deallocate the socket descriptor: Note: close function call
int close(int s); ⋮ int rc; int server_sock; ⋮ rc = close(server_sock);In the previous example socket server_sock is closed. The close call shuts down the socket descriptor server_sock and frees up its resources.