#include "win/winsock2.bi" ' CONSTants CONST Socket_Buffer_Size = 2048 ' Socket Send/Receive buffer size CONST Socket_Buffer_Get = 255 ' How many bytes to get per loop CONST Socket_Is_Closed = 0 ' Socket is closed, or not used. CONST Socket_Is_Open = 1 ' Socket is open. CONST Socket_Is_Listening = 2 ' Socket is listening. CONST Socket_Is_Connecting = 3 ' Socket is connecting. CONST Socket_Is_Connected = 4 ' Socket is connected. CONST Socket_Is_Closing = 5 ' Socket is closing connection. CONST Socket_Is_Error = 6 ' Socket encountered an error. ' Types TYPE Our_Socket_Type sSocket AS SOCKET ' Winsock assigns its own SOCKET data type for sSocket. State AS UBYTE ' This is the status. SendBuffer AS ZSTRING * Socket_Buffer_Size ' 2k is sufficient enough. SendBytes AS ULONG ' The amount of bytes to send. RecvBuffer AS ZSTRING * Socket_Buffer_Size ' 2k is sufficient enough. RecvBytes AS ULONG ' The amount of bytes to receive. END TYPE ' We'll use 3 sockets in our chat program. CONST Max_Sockets = 3 DIM SHARED Our_Sockets(1 TO Max_Sockets) AS Our_Socket_Type ' Our sockets' handles. DIM SHARED Listen_Socket AS UBYTE, Main_Socket AS UBYTE, HTTP_Socket AS UBYTE, PORT AS UINTEGER ' Socket handles used in Connect 4 FB. DECLARE SUB PrintErrorEnd (ErrorMessage$) ' Winsock specific calls. DECLARE SUB Winsock_Close () DECLARE SUB Winsock_Start () DECLARE FUNCTION Make_Socket_Close (BYREF This_Socket AS UBYTE) AS BYTE ' Close the socket. DECLARE FUNCTION Make_Socket_Open (BYREF This_Socket AS UBYTE) AS BYTE ' Open up a socket. DECLARE FUNCTION Make_Socket_Resolve (BYVAL stHostName AS STRING) AS INTEGER DECLARE FUNCTION Socket_New () ' Finds an unused socket to use. DIM SHARED DummyStringA$, WinsockVersion$ ' Custom string routines. DIM SHARED Key$, InsertKey ' Keyboard input stuff for later on. ' 640 x 480 SCREEN 18, 8, 2 Winsock_Start DummyStringA$ = STR(Make_Socket_Open(Main_Socket)) DummyStringA$ += STR(Make_Socket_Close(Main_Socket)) DummyStringA$ += " " + STR(Make_Socket_Resolve("127.0.0.1")) DO ' ======= MAIN LOOP ' Keyboard Key$ = INKEY ' Grab our key from keyboard. IF Key$ = CHR(255) + CHR(82) THEN InsertKey = InsertKey XOR 1 ' Toggle insert key state. ' Print version. LOCATE 1, 25: PRINT "Your version of Winsock is " + WinsockVersion$ ' Print Polling status. LOCATE 26, 5: PRINT DummyStringA$ LOOP UNTIL Key$ = CHR(27) OR Key$ = CHR(255) + "k" ' == END OF MAIN LOOP ' Close Winsock and end the program! Winsock_Close FUNCTION Make_Socket_Close (BYREF This_Socket AS UBYTE) AS BYTE ' Winsock's routine to close down both incoming and outgoing networking operations. ShutDown Our_Sockets(This_Socket).sSocket, SD_BOTH ' ow disconnect the handle and check to see if it's closed completely. IF CloseSocket(Our_Sockets(This_Socket).sSocket) = 0 THEN Our_Sockets(This_Socket).State = Socket_Is_Closed ' Closed socket This_Socket = 0 ' Unassign socket Make_Socket_Close = -1 ' Return true for successful close down. ELSE Our_Sockets(This_Socket).State = Socket_Is_Error ' Failed to close socket Make_Socket_Close = 0 END IF END FUNCTION FUNCTION Make_Socket_Open (BYREF This_Socket AS UBYTE) AS BYTE ' Set Non-blocking mode on. DIM NonBlocking AS LONG NonBlocking = 1 ' Get unused Socket from our routine! This_Socket = Socket_New IF This_Socket = -1 THEN EXIT FUNCTION ' No more sockets available! ' Winsock's open socket routine Our_Sockets(This_Socket).sSocket = OpenSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP) /' Winsock's socket protocol parameters: This is what we'll use. AF_INET (As opposed to AF_INET6) Since we're using IPv4 instead of IPv6 for IP addresses. SOCK_STREAM (As opposed to SOCK_DGRAM) Since we're using a connection-based socket, we use this. IPPROTO_TCP (As opposed to IPPROTO_UDP) TCP is slower than UDP, but ensures reliability and delivers data in the correct order. The first parameter is the address family. We'll be using IPv4. While IPv6 is slowly catching up (as of now), IPv4 is still the standard. It's also easier to type since it only goes up to 15 characters with decimal numbers. The second parameter is simply telling it we're using a stream (constant connection, kinda like a live phone connection) that will be used for TCP. For chatting, we're using TCP protocol. TCP is a connection-based real time protocol. Unlike UDP (Datagram), TCP is designed to make sure you receive packets (chunks of data), and in the correct order they were sent out. UDP (Datagram) is faster, doesn't need a constant streaming connection, however, it doesn't check to see if you received your packets in order, or if you even got the packets at all! For this reason, TCP is much easier to work with since it's designed to be reliable. '/ IF Our_Sockets(This_Socket).sSocket = NULL THEN EXIT FUNCTION /' The ioctlsocket function controls the I/O mode of a socket, which you will put your sockets into non-blocking mode. The FIONBIO and @lNonBlocking mode is basically telling FIONBIO (non-blocking command) to equal to 1, meaning non-blocking is now enabled (nonzero value enables it). Since you have non-blocking mode on, this will prevent the recv() function from halting your program. '/ IF ioctlsocket(Our_Sockets(This_Socket).sSocket, FIONBIO, @NonBlocking) = -1 THEN EXIT FUNCTION Our_Sockets(This_Socket).State = Socket_Is_Open ' Now tell it that the socket is open. Make_Socket_Open = -1 END FUNCTION FUNCTION Make_Socket_Resolve (BYVAL stHostName AS STRING) AS INTEGER ' Internet address and host entry header. DIM ia AS in_addr DIM hostentry AS hostent PTR ' Check if it's an actual ip address ia.S_addr = inet_addr(stHostName) ' This converts a string containing an IPv4 dotted-decimal ' address into a proper address for the IN_ADDR structure. IF ia.S_addr = INADDR_NONE THEN ' IF not, assume it's a name. Use Winsock's routine to resolve it. hostentry = gethostbyname(stHostName) IF hostentry = 0 THEN EXIT FUNCTION Make_Socket_Resolve = *CAST(INTEGER PTR, *hostentry->h_addr_list) ELSE ' Just return the address Make_Socket_Resolve = ia.S_addr END IF END FUNCTION SUB PrintErrorEnd (ErrorMessage$) ' END Program with error. ' Here, you'd like to know why you got an error, so print it out on screen! CLS COLOR 15 WSACleanUp PRINT ErrorMessage$ PRINT "Error code: (IF applicable)", WSAGetLastError SLEEP END END SUB FUNCTION Socket_New DIM Check_This_Socket AS BYTE ' Look through all of our sockets, and find one that's not used. FOR Check_This_Socket = 1 TO UBOUND(Our_Sockets) IF Our_Sockets(Check_This_Socket).State = Socket_Is_Closed THEN ' New unused socket found, use it Our_Sockets(Check_This_Socket).sSocket = 0 ' Making sure everything is NULL. Our_Sockets(Check_This_Socket).SendBuffer = "" Our_Sockets(Check_This_Socket).SendBytes = 0 Our_Sockets(Check_This_Socket).RecvBuffer = "" Our_Sockets(Check_This_Socket).RecvBytes = 0 Socket_New = Check_This_Socket ' Return the value of the unused socket that was found. EXIT FOR END IF NEXT Check_This_Socket END FUNCTION SUB Winsock_Close ' Winsock's shut down routine that cleans up everything associated with Winsock. WSACleanUp END END SUB SUB Winsock_Start ' Winsock's data structure has to be used to retrieve our version info. DIM MakeOurWSAData AS WSAdata ' Fire up Winsock! We're requesting v2.0 IF WSAStartup(MAKEWORD(2, 0), @MakeOurWSAData) THEN SELECT CASE WSAGetLastError CASE WSASYSNOTREADY PRINT "Underlying Network subsystem is not ready." CASE WSAVERNOTSUPPORTED PRINT "The requested version is not supported." CASE WSAEINPROGRESS PRINT "A blocking Windows Sockets 1.1 operation is in progress." CASE WSAEPROCLIM PRINT "Winsock's usage has reached its limits by other programs." CASE WSAEFAULT PRINT "The second parameter is not a valid WSAData type." CASE ELSE PRINT "Unknown error. Error code (if any): ", WSAGetLastError END SELECT SLEEP END END IF /' Even though we know that 2.0 (or higher) is supported, we will go ahead and check the highest version you have available. You may now use the returned values from MakeOurWSAData to pull up the highest available version of Winsock. '/ OurVersionMajor$ = LTRIM(STR(MakeOurWSAData.wHighVersion AND 255)) OurVersionMinor$ = LTRIM(STR(MakeOurWSAData.wHighVersion SHR 8)) WinsockVersion$ = "v" + OurVersionMajor$ + "." + OurVersionMinor$ END SUB