Forum > Unix
Textfiles and unix-domain sockets
MarkMLl:
UD sockets are a nice feature, but I think their real strength is as a "short circuit" if data is to be transferred locally (e.g. an X11 connection between client and server on the same system).
(Named) FIFOs are somewhat easier to work with if a stream (rather than a sequence of datagrams) is to be handled and there is absolutely no need to map it over the network.
In either case a nodding familiarity with POSIX capabilities is useful, so that if the (name representing the) socket or FIFO has to be in a directory owned by root a program can manipulate it during startup.
MarkMLl
RickE:
Here is the "Sockets_Text_Unit" required above in the Uses clause;
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- UNIT Sockets_Text_Unit;{****************************************************************************** FREEPASCAL SOCKETS TEXT FILE I/O INTERFACE******************************************************************************} {*****************************************************************************}INTERFACE{$PACKRECORDS C}{*****************************************************************************}{Text FileType RecordRead + Write Support Types and Constants from FreePascal System Unit textrec.inc const TextRecNameLength = 256; TextRecBufSize = 256; type TFileTextRecChar = widechar; TLineEndStr = string [3]; TextBuf = array[0..TextRecBufSize-1] of ansichar; TTextBuf = TextBuf; TextRec = Record Handle : THandle; Mode : longint; bufsize : SizeInt; _private : SizeInt; bufpos, bufend : SizeInt; bufptr : ^textbuf; openfunc, inoutfunc, flushfunc, closefunc : codepointer; UserData : array[1..32] of byte; name : array[0..textrecnamelength-1] of TFileTextRecChar; LineEnd : TLineEndStr; Line ending to use buffer : textbuf; End;} Procedure Assign_SocketFD_to_SocketIO_TextChannels( param_SocketFD: Longint; Var param_var_Input_TextFile: Text; Var param_var_Output_TextFile: Text ); {*****************************************************************************}IMPLEMENTATIONUses SysUtils;{*****************************************************************************} Function Read_SocketInput_TextChannel( var param_var_TextRecord: TextRec ): Longint; var loc_var_CharCount : longint; Begin { System Read from Socket FileDescriptor into Socket Text Buffer. } loc_var_CharCount := FileRead( param_var_TextRecord.handle, param_var_TextRecord.bufptr^, param_var_TextRecord.bufsize ) ; If (loc_var_CharCount < 0) then Exit(-1) ; { Returns number of bytes read to TextRecord.BufEnd. } param_var_TextRecord.BufEnd := loc_var_CharCount ; { ReSet Read TextRecord buffer position to 0 when done. } param_var_TextRecord.bufpos := 0 ; { Done } Read_SocketInput_TextChannel := 0 ; End; { Function Read_SocketInput_TextChannel } { ============================================================================ }Function Write_SocketOutput_TextChannel( var param_var_TextRecord: TextRec ): Longint; var loc_var_CharCount : longint; Begin { System Write from Socket Text Buffer into Socket FileDescriptor. } { Writes bufpos number of bytes. } loc_var_CharCount := FileWrite( param_var_TextRecord.handle, param_var_TextRecord.bufptr^, param_var_TextRecord.bufpos ); If (loc_var_CharCount < 0) then Exit(-1) ; { ReSet buffer position to 0 when done. } param_var_TextRecord.bufpos := 0; { Done } Write_SocketOutput_TextChannel := 0; End; { Function Write_SocketOutput_TextChannel } { ============================================================================ }Function Flush_SocketOutput_TextChannel( var param_var_TextRecord: TextRec ): Longint; Begin { If needs flush. } If ( param_var_TextRecord.bufpos > 0 ) Then Write_SocketOutput_TextChannel( param_var_TextRecord ); { Done } Flush_SocketOutput_TextChannel := 0; End; { Function Flush_SocketOutput_TextChannel } { ============================================================================ }{ Assign two FreePascal Text FileTypes to Socket FileDescriptor for Read, Write calls. } Procedure Assign_SocketInput_TextChannel( param_SocketFD: Longint; Var param_var_Input_TextFile: Text ); Begin FillChar(TextRec( param_var_Input_TextFile), SizeOf(TextRec), 0 ); TextRec(param_var_Input_TextFile).Mode := fmInput; TextRec(param_var_Input_TextFile).Handle := param_SocketFD ; TextRec(param_var_Input_TextFile).InOutFunc := @Read_SocketInput_TextChannel ; TextRec(param_var_Input_TextFile).FlushFunc := nil ; TextRec(param_var_Input_TextFile).OpenFunc := nil ; TextRec(param_var_Input_TextFile).CloseFunc := nil ; TextRec(param_var_Input_TextFile).BufSize := TextRecBufSize ; TextRec(param_var_Input_TextFile).Bufptr := @TextRec(param_var_Input_TextFile).Buffer; TextRec(param_var_Input_TextFile).LineEnd := #10; End; { Procedure Assign_SocketInput_TextChannel } Procedure Assign_SocketOutput_TextChannel( param_SocketFD: Longint; Var param_var_Output_TextFile: Text ); Begin FillChar( TextRec(param_var_Output_TextFile), SizeOf(TextRec), 0 ); TextRec(param_var_Output_TextFile).Mode := fmOutput; TextRec(param_var_Output_TextFile).Handle := param_SocketFD; TextRec(param_var_Output_TextFile).InOutFunc := @Write_SocketOutput_TextChannel; TextRec(param_var_Output_TextFile).FlushFunc := @Flush_SocketOutput_TextChannel; TextRec(param_var_Output_TextFile).OpenFunc := nil ; TextRec(param_var_Output_TextFile).CloseFunc := nil ; TextRec(param_var_Output_TextFile).BufSize := TextRecBufSize; TextRec(param_var_Output_TextFile).Bufptr := @TextRec(param_var_Output_TextFile).Buffer; TextRec(param_var_Output_TextFile).LineEnd := #10; End; { Procedure Assign_SocketOutput_TextChannel } { ============================================================================ }{ Interface Procedure }Procedure Assign_SocketFD_to_SocketIO_TextChannels( param_SocketFD: Longint; Var param_var_Input_TextFile: Text; Var param_var_Output_TextFile: Text ); Begin { First, Assign the reading channel.} Assign_SocketInput_TextChannel( param_SocketFD, param_var_Input_TextFile ); { Now, Assign the writing channel. } Assign_SocketOutput_TextChannel( param_SocketFD, param_var_Output_TextFile ); End; { Procedure Assign_SocketFD_to_SocketIO_TextChannels } {******************************************************************************Initialize Unit******************************************************************************}Begin{ nothing }End.
I could also load sample server and client programs. Rather nice is how the client can also bind to a filename.
Sincere thanks. Rick.
MarkMLl:
--- Quote from: RickE on March 07, 2022, 09:28:23 pm ---Rather nice is how the client can also bind to a filename.
--- End quote ---
Yes, but in the case of UD sockets watch out for the case where a filesystem name has been created but there is no longer an associated process. Particularly if deletion requires elevated privilege.
MarkMLl
RickE:
I hope you find these two little test programs, UD server and client, fun to try compile and run.
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Program LocalPacketSocket_Server;{$PACKRECORDS C} Uses BaseUnix, LocalPacketSockets_Text_Unit; Const pgm_const_ServerName = 'Socket_LocalServer.soc' ; pgm_const_ConnectQueueLimit = 3 ; Var pgm_var_SocketFD, pgm_var_ConnectFD: Longint; pgm_var_Connect_ClientName: String[107]; pgm_var_ConnectCount: Longint; pgm_var_Accept_New_Connections: Boolean; pgm_var_Socket_TextInput, pgm_var_Socket_TextOutput: Text; pgm_var_Message_String: String[255]; { ============================================================================ }Procedure Handle_Socket_Error( const socket_error_message: string ); Begin writeln( socket_error_message ); halt; End; { ============================================================================ }Begin { Program LocalPacketSocket_Server }{*** Initialize variables. ***} pgm_var_Connect_ClientName := '' ; pgm_var_ConnectCount := 0 ; pgm_var_Accept_New_Connections := True ; pgm_var_Message_String := '' ; {*** Initialize file system. ***} FpUnlink( pgm_const_ServerName ); { CreateNew Server Socket FileDescriptor. } If ( CreateNew_LocalPacketSocket_OK( pgm_var_SocketFD ) = False ) Then Handle_Socket_Error( 'CreateNew Socket Error ==>> Quit !! ' ); { Bind; Assign Local FileName to Server Socket FileDescriptor. } If (Bind_LocalPacketSocket_PathName_OK( pgm_var_SocketFD, pgm_const_ServerName ) = False ) Then Handle_Socket_Error( 'Bind Socket Error ==>> Quit !! ' ); { Run Unix Local Server }{ Listen; Enable and Wait For New Client ConnectRequests. } If ( Listen_LocalPacketSocket_OK( pgm_var_SocketFD, pgm_const_ConnectQueueLimit ) = False ) Then Handle_Socket_Error( 'Listen Socket Error ==>> Quit !! ' ); { Notify User that Server Program is Waiting for Client ConnectRequests. } Writeln; Writeln( 'Starting Unix Local Packet Server using FileName = ', pgm_const_ServerName ); Writeln( 'With Server Socket FileDescriptor = ', pgm_var_SocketFD ); Writeln( 'Server is now Listening for Connect Requests from Clients.' ); Writeln( 'Next, run a Unix Local Packet Socket Client connect program in a separate xterm.' ); Writeln; {The accept() system call is used with connection-based socket types (SOCK_STREAM, SOCK_SEQPACKET). It extracts the first connection request on the queue of pending connections for the listening socket, sockfd, creates a new connected socket, and returns a new file descrip- tor referring to that socket. The newly created socket is not in the listening state. The original socket sockfd is unaffected by this call. If no pending connections are present on the queue, and the socket is not marked as nonblocking, accept() blocks the caller until a connec- tion is present. If the socket is marked nonblocking and no pending connections are present on the queue, accept() fails with the error EAGAIN or EWOULDBLOCK.} While pgm_var_Accept_New_Connections Do Begin { Accept Function Waits (default) while Listening for New Client ConnectRequest. } { Accept; Create New Socket Interface and Assign Server New TextStream Socket I/O Channels to New Client. } If ( AcceptRequest_NewTextPacketSocket_OK( pgm_var_SocketFD, pgm_var_ConnectFD, pgm_var_Connect_ClientName, pgm_var_Socket_TextInput, pgm_var_Socket_TextOutput ) = True ) Then { Use Unix Text Stream Socket Connection } Begin { Notify User of Begin Client Connection. } Writeln ; Writeln( 'Begin Connect to ClientName = ', pgm_var_Connect_ClientName ); Writeln( 'on Server AcceptConnect FileDescriptor = ', pgm_var_ConnectFD ); Writeln ; { Notify Client program of New Connection. } Writeln( pgm_var_Socket_TextOutput, pgm_var_Connect_ClientName, ', this is a message from ', pgm_const_ServerName ); { Serve the connection until it is finished. } Repeat Readln( pgm_var_Socket_TextInput, pgm_var_Message_String ); Writeln( 'Received message "', pgm_var_Message_String, '"' ); Writeln ; Until ( pgm_var_Message_String = 'quit' ); { Notify Server program of End Client Connection. } Writeln ; Writeln( 'End Connect to ClientName = ', pgm_var_Connect_ClientName ); Writeln( 'Close Connection FileDescriptor = ', pgm_var_ConnectFD ); Writeln ; { Close Server AcceptConnect FileDescriptor.} FpClose( pgm_var_ConnectFD ); { Clean up Server Variables. } pgm_var_Connect_ClientName := '' ; pgm_var_Accept_New_Connections := False ; End Else Begin pgm_var_Accept_New_Connections := False ; FpUnlink( pgm_const_ServerName ); Handle_Socket_Error( 'Server : Accept : ' ); End; End ; { While..Do } { Notify User that Server program is Quitting. } Writeln ; Writeln( 'Quitting Server using Socket FileDescriptor = ', pgm_var_SocketFD ) ; Writeln ; { Remove Named File } FpClose( pgm_var_SocketFD ) ; FpUnlink( pgm_const_ServerName ); End. { Program LocalPacketSocket_Server } Program LocalPacketSocket_ClientLoop; Uses BaseUnix, LocalPacketSockets_Text_Unit; Const pgm_const_ServerName = 'Socket_LocalServer.soc' ; Var pgm_var_ClientName : String[100] ; pgm_var_ClientSocketFD : Longint; pgm_var_Socket_TextInput, pgm_var_Socket_TextOutput : Text; pgm_var_Message_String : String[255]; { ============================================================================ }Procedure Handle_Socket_Error( const socket_error_message : string ); Begin writeln ( socket_error_message ); halt; End; { ============================================================================ }Begin { Initialize program variables } pgm_var_ClientName := 'Socket_LocalClient.soc' ; FpUnlink( pgm_var_ClientName ); { CreateNew Socket FileDescriptor. } If ( CreateNew_LocalPacketSocket_OK( pgm_var_ClientSocketFD ) = False ) Then Handle_Socket_Error( 'CreateNew Socket Error ==>> Quit !! ' ); { Bind; Assign Named File to Socket FileDescriptor. } If (Bind_LocalPacketSocket_PathName_OK( pgm_var_ClientSocketFD, pgm_var_ClientName ) = False ) Then Handle_Socket_Error( 'Bind Socket Error ==>> Quit !! ' ); { ConnectRequest; Create New Socket Interface and Assign Client Socket Channels to Named Server. } If (ConnectRequest_NewTextPacketSocket_OK( pgm_var_ClientSocketFD, pgm_const_ServerName, pgm_var_Socket_TextInput, pgm_var_Socket_TextOutput) = False) Then Handle_Socket_Error( 'ConnectRequest Socket Error ==>> Quit !! ' ); {*** Use New Connection to Server. ***}{ Notify Client program Begin Connection. } Writeln ; Writeln( pgm_var_ClientName, ' Begin Connect to ServerName = ', pgm_const_ServerName ); Writeln( 'Client FileDescriptor = ', pgm_var_ClientSocketFD ); Writeln ; { Read messages from connected input channel. } Readln( pgm_var_Socket_TextInput, pgm_var_Message_String ); WriteLn( pgm_var_Message_String ); Writeln ; { Write messages to connected output channel. } Writeln( pgm_var_Socket_TextOutput, 'just a quickie' ); Writeln ; Write( 'Hit return to continue.' );Readln(); Writeln( pgm_var_Socket_TextOutput, 'just a longsecond quickie' ) ; Writeln ;Write( 'Hit return to continue.' );Readln(); Writeln( pgm_var_Socket_TextOutput, 'third quickie' ) ; Writeln ;Write( 'Hit return to quit.' );Readln(); Writeln( pgm_var_Socket_TextOutput, 'quit' ); { Notify Client program End Connection. } Writeln ; Writeln( pgm_var_ClientName, ' Ending Connect to ServerName = ', pgm_const_ServerName ); Writeln( 'Close Client FileDescriptor = ', pgm_var_ClientSocketFD ); Writeln ; { Close and Remove Client File. } FpClose( pgm_var_ClientSocketFD ) ; FpUnlink( pgm_var_ClientName ); End. { Program LocalPacketSocket_ClientLoop }
It works on my 32 bit opensuse 13.2.
Best of luck with all your ambitions. Most important is to remember the suse motto, "have a lot of fun." I will always be grateful to the suse linux community, the tcl/tk community, and the freepascal community for keeping me what I regard as sane. Amazing treasures.
Navigation
[0] Message Index
[*] Previous page