700 likes | 876 Views
Network Programming. TCP socket & UDP socket. Socket Programming with Windows OS. 1982 - Berkeley Software Distributions introduced sockets as an interface for communication between local processes 1986 - Berkeley extended the socket interface for use over the TCP/IP with UNIX
E N D
Network Programming TCP socket & UDP socket
Socket Programming with Windows OS • 1982 - Berkeley Software Distributions introduced sockets as an interface for communication between local processes • 1986 - Berkeley extended the socket interface for use over the TCP/IP with UNIX • Today many applications (FTP, Telnet, etc) depend on these interfaces
Socket Programming with Windows OS • Socket • a programming interface • a logical, file handle like, construct that an application uses for communication (everything in Unix is a file) • not restricted to TCP/IP
WinSock • Derived from Berkeley Sockets (Unix) • includes many enhancements for programming in the windows environment • Open interface for network programming under Microsoft Windows • API freely available • Multiple vendors supply winsock • Source and binary compatibility • Collection of function calls that provide network services
Socket Programming with Windows OS • Communication protocols • connection oriented (Transmission Control Protocol - TCP/IP) • connectionless (User Datagram Protocol -UDP and Inter-network Packet Exchange - IPX)
Socket Programming with Windows OS • Microsoft proposed an industry wide socket standard for Windows OS, called as Windows Socket Interface or WinSock. • Windows socket based applications use the WinSock interface to access the default Windows WinSock implementation, WinSock.dll or an alternative implementation such as, the FTP WinSock.dll
Windows Socket, Protocols and Applications Application FTP WinSock.dll WinSock.dll Remote Access Service (RAS) TCP/IP IPX AppleTalk NetBIOS FTP TCP/IP Modem Network Drivers Phone Line LAN
Differences BetweenBerkeley and WinSock • Socket is an int data type in Berkeley, but a SOCKET data type in WinSock • SOCKET_ERROR is produced by all WinSock functions, but negative one (-1) in Berkeley • Applications must call WSAStartup() before calling any WinSock functions, and should call the WSACleanup() function before terminating
Step 1: Define your socket (upload Winsock DLL) Winsock version 1.1 Step 2: Initialize your socket Initialize Winsock /* This stuff initializes winsock */ WSAStartup(wVersionRequested, &wsaData); /* Create a socket */ My_SocketID = socket ( ….. ); Step 3: Start using it void main (void) { /* The following two lines needed for Window's socket */ WORD wVersionRequested = MAKEWORD(1,1); /* Stuff for WSA functions */ WSADATA wsaData; /* Stuff for WSA functions */
Winsock DLL • If call Winsock functions before uploading Winsock DLL, SOCKET-ERROR will be returned. • Uploading Winsock DLL by calling WSAStartup int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData ); • wVersionRequested Winsock DLL version • X (high order): sub-version • Y (low order): main version • MAKEWORD(X,Y)gives the correct wVersionRequested value
Clear winsock After you call “closesocket” function but before your program is terminated /* This stuff cleans-up winsock */ WSACleanup( );
#include <winsock2.h> //包含Winsock头文件 void main(void){ WSADATA wsaData; // 初始化 Winsock 版本 2.2 if ((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0){ printf("WSAStartup failed with error %d\n", Ret); return; } // 在这里开始进行Winsock通信编程 // 当应用结束时调用 WSACleanup if (WSACleanup() == SOCKET_ERROR){ printf("WSACleanup failed with error %d\n", WSAGetLastError()); } }
TCP Sockets Programming • Creating a passive mode (server) socket. • Establishing an application-level connection. • Client/Server handshaking • before sending or receiving data • client must explicitly connect to server • server must explicitly accept client • client will not pass connect() until server accepts client • server will not pass accept() until client connects to server • Send/receive data. • Terminating a connection.
1 digit integer send() close() Format of time stamp: “HH:MM:SS” SERVER “*” indicates a blocking function call. socket() CLIENT socket() bind() 1: Connection Request * listen() connect() * accept() Client ID# send() * recv() 2. Send a command * recv() 3. Receive the result
Returns socket ID on success “AF_INET” = Use IP protocol socket ( ) function “SOCK_STREAM” = Use TCP Always 0 unsigned int socket_id = socket (AF_INET, SOCK_STREAM, 0);
Basic Socket Calls (socket) SOCKET socket (int family, int type, int protocol);
socket (continued) • SOCKET socket (int family, int type, int protocol); • family is address family • AF_INET // internet protocols • AF_UNIX // unix internal protocols • AF_NS // Xerox NS protocols • AF_IMPLINK // Interface Message Processor • type is • SOCK_STREAM // stream socket • SOCK_DGRAM // datagram socket • SOCK_RAW // raw socket • protocol is usually zero in applications programming
Return code (< 0 if error) Socket ID returned by socket function The sockaddr_in structure to specify port # and IP address of this machine (server machine) Bind ( ) function The byte size of the Sockaddr_in structure int status = bind (socket_id, (struct sockaddr_in *) my_addr, sizeof(my_addr));
Basic Socket Calls (bind) int bind(SOCKET sockfd, struct sockaddr* addr, int addrLen);
bind (continued) int bind (SOCKET sockfd, struct sockaddr* addr, int addrLen); • sockfd was returned from the socket() call • addr is pointer to a sockaddr_in structure that contains the server IP address and port number • struct sockaddr_in • short sin_family // address family • u_short sin_port // port number • struct in_addr sin_addr //IP address (32-bits) • addrLen - sizeof (struct sockaddr_in)
Step 1: You instantiate the structure /* Set My(client's) IP Address ---------------------------------------- */ my_addr.sin_family= AF_INET; /* Address Family To Be Used */ my_addr.sin_port = htons (MY_PORT_NUM); /* Port number to use */ my_addr.sin_addr.s_addr = htonl (INADDR_ANY); /* My IP address */ The “sock_addr” structure Step 2: Fill up the components struct sockaddr_in my_addr; /* My (client) Internet address */
Filling the sockaddr_in structure • INADDR_ANY is used for accepting connections on any local interface if the system is multi-homed • We assign a zero port number when filling the sockaddr_in data structure, if we want a free port to be allocated to asocket during the bind() procedure • htonl(), htons() handle byte-ordering differences between computer architectures and network protocols • redundant in Sun’s sparc • needed in x86 architectures
Address Structures • struct sockaddr { // socket address information u_short sa_family; // address family char sa_data[14];// up to 14 bytes of direct address }; • struct in_addr { // internet address u_long s_addr; // socket address };
Address Structures • struct sockaddr_in {//socket address internet short sin_family; //2 bytes u_short sin_port;//2 bytes port number struct in_addr sin_addr; //4 bytes net ID, host ID char sin_zero[8]; //8 bytes unused }; • There are also some functions to convert from and to native types. • The internet address for a socket-based application composed of two pieces • two-byte port number (sin_port) > 1023 • four-byte network address (sin_addr)
gethostname() • Get the name of the host the program is running on. • int gethostname(char *hostname, int bufferLength) • Upon return hostname holds the name of the host • bufferLength provides a limit on the number of bytes that gethostname can write to hostname.
Domain Name Library Routine (gethostbyname) • gethostbyname(): Given a host name (such as ctec.xjtu.edu.cn), get host information. • struct hostent* getbyhostname(char *hostname) • char* h_name; // official name of host • char** h_aliases; // alias list • short h_addrtype; // address family (e.g., AF_INET) • short h_length; // length of address (4 for AF_INET) • char** h_addr_list; // list of addresses (null pointer terminated)
Internet Address Library Routines(inet_addr() and inet_ntoa()) • unsigned long inet_addr(char *address); • converts address in dotted form to a 32-bit numeric value in network byte order • (e.g., “202.117.50.26”) • char* inet_ntoa(struct in_addr address) • struct in_addr • address.S_addr is the long int representation
Internet Address Library Routines(gethostbyaddr) • Get the name of the host the program is running on. • struct hostent* gethostbyaddr(char *address, int addressLength, int type) • address is in network byte order • addressLength is 4 if type is AF_INET • type is the address family (e.g., AF_INET)
Byte Order - Host to network • u_long htonl (u_long hostlong); • u_short htons (u_short short);
Byte Order – Network to Host • u_long ntohl (u_long hostlong); • u_short ntohs (u_short short);
Example: Build SOCKADDR_IN Sockaddr_in InternetAddr; int nPortId = 5150; InternetAddr.sin_family = AF_INET; //converts address in dotted form to a //32-bit numeric value in network byte order //then assign it to sin_addr InternetAddr.sin_addr.s_addr = inet_adddr(“202.117.50.26"); //nPortId is in host order. //Convert nPortId to network byte order, //then assign it to sin_port. InternetAddr.sin_port = htons (nPortId);
Example: bind SOCKET s; sockaddr_in addr; // Internet address // 创建流Socket s = socket(AF_INET, SOCK_STREAM, 0); if (s != INVALID_SOCKET){ // 填充地址信息 addr.sin_family = AF_INET; addr.sin_port = htons(2000); addr.sin_addr.s_addr = htonl(INADDR_ANY); // 将Socket和它的地址绑定 if (bind(s, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) printf("bind() generated error %d", WSAGetLastError()); else ... }
Return code (< 0 if error) Socket ID returned by socket function listen ( ) function The size of the connection request buffer int status = listen (socket_id, 3);
Basic Socket Calls (listen) int listen (SOCKET sockfd, int backlog);
listen (continued) int listen (SOCKET sockfd, int backlog); • sockfd was returned from the socket() call • 1<=backlog<=5 • Backlog specifies the number of connection requests that may be simultaneously waiting for service. • This is NOT the number of clients that can be receiving service simultaneously.
duplicated socket ID (< 0 if error) Socket ID returned by socket function accept ( ) function The sockaddr_in structure for a connecting client The size of the sockaddr_in structure for connecting client unsingned int child_sock = accept (socket_id, (struct sockaddr_in *) client_addr, sizeof (client_addr);
Basic Socket Calls (accept) SOCKET accept (SOCKET s, struct sockaddr* addr, int* pointerToAddrLen);
accept (continued) SOCKET accept (SOCKET s, struct sockaddr* addr, int* pointerToAddrLen); • s was returned from the socket() call • addr is pointer to a sockaddr structure that will contain the client information • struct sockaddr • unsigned short sa_family // Address Family • AF_INET, AF_UNIX, AF_NS, AF_IMPLINK • char sa_data[14] // up to 14 bytes of protocol-specific address • pointerToAddrLen can be set by accept • The returned socket provides communication with the client.
SOCKET s; // 监听Socket SOCKET clientSocket; // 客户Socket sockaddr_in addr; // 服务器的绑定地址 sockaddr_in clientAddr; // 连接的客户地址 IN_ADDR clientIn; // 客户IP地址 int nClientAddrLen; // 客户地址结构长度 // 创建流Socket s = socket(AF_INET, SOCK_STREAM, 0); if (s != INVALID_SOCKET){ // 填充地址信息 addr.sin_family = AF_INET; addr.sin_port = htons(2000); addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定Socket if (bind(s, (sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR){ // 监听连接 if (listen(s, 3) != SOCKET_ERROR){ // 设置客户地址结构长度 nClientAddrLen = sizeof(clientAddr); // 接受连接 clientSocket = accept(s, (sockaddr*)&clientAddr, &nClientAddrLen); accept example if (clientSocket == INVALID_SOCKET){ printf("accept() generated error %d", WSAGetLastError()); } else{ memcpy(&clientIn, &clientAddr.sin_addr.s_addr, 4); printf("accept() ok: client IP address is %s, port is %d",inet_ntoa(clientIn), ntohs(clientAddr.sin_port)); ... } } } }
BasicSocket Calls (connect) int connect (SOCKET s, struct sockaddr* addr, int sizeOfAddr);
SOCKET s; sockaddr_in serverAddr; s = socket(AF_INET, SOCK_STREAM, 0); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(2000); serverAddr.sin_addr.s_addr = inet_addr("202.117.50.26"); if(connect(s, (sockaddr*)&serverAddr, sizeof(serverAddr))== SOCKET_ERROR){ printf("connect () failure: %d", WSAGetLastError()); } else{ ... } connect Example
Return code (< 0 if error) Socket ID returned by socket function The input (receive) buffer as a character string recv ( ) function The maximum buffer size Always 0 On success, the number of bytes received int status = recv (socket_id, in_buffer, MAX_BUFFER_SIZE, 0); Example: char in_buffer [MAX_BUFFER]
Basic Socket Calls (recv) int recv(SOCKET s, char* bytesToReceive, int nBytes, int flags);
recv (continued) int recv (SOCKET s, char* bytesToReceive, int nBytes, int flags); • s was returned from the socket() call • bytesToReceive is a pointer to the data buffer • nBytes is the maximum number of bytes to receive • flags • 0, MSG_DONTROUTE, or MSG_OOB • Note: There is no guarantee that recv will recv all the data requested. The number of bytes that recv actually received is returned by the function. It may be necessary to call recv repeatedly in a loop to achieve the desired result.
Example #define BUFSIZE 1024 SOCKET s; char buf[BUFSIZE]; //缓冲区 int bytesRecv; // 创建socket并连接服务器 ... bytesRecv = recv(s, buf, BUFSIZE, 0); if( bytesRecv == SOCKET_ERROR ){ printf("recv() generated error %d", WSAGetLastError()); } else if(bytesRecv == 0){ printf("The peer has closed the connection."); closesocket(s); } else{ // 处理缓冲区的数据 }
Return code (< 0 if error) Socket ID returned by socket function The output (send) buffer as a character string send ( ) function The maximum buffer size Always 0 On success, the number of bytes actually sent int status = send (socket_id, out_buffer, MAX_BUFFER_SIZE, 0);
Basic Socket Calls (send) int send (SOCKET s, const char* bytesToSend, int nBytes, int flags);
send (continued) int send (SOCKET s, const char* bytesToSend, int nBytes, int flags); • s was returned from the socket() call • bytesToSend is a pointer to the data to send • nBytes is the number of bytes to send • flags • e.g., MSG_OOB • Note: There is no guarantee that send will send all the data requested. The number of bytes that send actually transmits is returned as a the result of the function. It may be necessary to call send repeatedly in a loop to achieve the desired result.
Example // Sample code that shows repeated calls to send int mustSend (SOCKET s, const char* bytesToSend, int nBytes, int flags) { int bytesSent = 0; while(bytesSent < nBytes) { bytesSent += send(s, bytesToSend+bytesSent, nBytes-bytesSent, flags); } return(bytesSent); }