Date: 2025-03-29T05:58:43+00:00

Actual source code: send.c

      1: #include <petscsys.h>

      3: #if defined(PETSC_NEEDS_UTYPE_TYPEDEFS)
      4: /* Some systems have inconsistent include files that use but do not
      5:    ensure that the following definitions are made */
      6: typedef unsigned char  u_char;
      7: typedef unsigned short u_short;
      8: typedef unsigned short ushort;
      9: typedef unsigned int   u_int;
     10: typedef unsigned long  u_long;
     11: #endif

     13: #include <errno.h>
     14: #include <ctype.h>
     15: #if defined(PETSC_HAVE_MACHINE_ENDIAN_H)
     16:   #include <machine/endian.h>
     17: #endif
     18: #if defined(PETSC_HAVE_UNISTD_H)
     19:   #include <unistd.h>
     20: #endif
     21: #if defined(PETSC_HAVE_SYS_SOCKET_H)
     22:   #include <sys/socket.h>
     23: #endif
     24: #if defined(PETSC_HAVE_SYS_WAIT_H)
     25:   #include <sys/wait.h>
     26: #endif
     27: #if defined(PETSC_HAVE_NETINET_IN_H)
     28:   #include <netinet/in.h>
     29: #endif
     30: #if defined(PETSC_HAVE_NETDB_H)
     31:   #include <netdb.h>
     32: #endif
     33: #if defined(PETSC_HAVE_FCNTL_H)
     34:   #include <fcntl.h>
     35: #endif
     36: #if defined(PETSC_HAVE_IO_H)
     37:   #include <io.h>
     38: #endif
     39: #if defined(PETSC_HAVE_WINSOCK2_H)
     40:   #include <Winsock2.h>
     41: #endif
     42: #include <sys/stat.h>
     43: #include <../src/sys/classes/viewer/impls/socket/socket.h>

     45: #if defined(PETSC_NEED_CLOSE_PROTO)
     46: PETSC_EXTERN int close(int);
     47: #endif
     48: #if defined(PETSC_NEED_SOCKET_PROTO)
     49: PETSC_EXTERN int socket(int, int, int);
     50: #endif
     51: #if defined(PETSC_NEED_SLEEP_PROTO)
     52: PETSC_EXTERN int sleep(unsigned);
     53: #endif
     54: #if defined(PETSC_NEED_CONNECT_PROTO)
     55: PETSC_EXTERN int connect(int, struct sockaddr *, int);
     56: #endif

     58: static PetscErrorCode PetscViewerDestroy_Socket(PetscViewer viewer)
     59: {
     60:   PetscViewer_Socket *vmatlab = (PetscViewer_Socket *)viewer->data;

     62:   PetscFunctionBegin;
     63:   if (vmatlab->port) {
     64:     int ierr;

     66: #if defined(PETSC_HAVE_CLOSESOCKET)
     67:     ierr = closesocket(vmatlab->port);
     68: #else
     69:     ierr = close(vmatlab->port);
     70: #endif
     71:     PetscCheck(!ierr, PETSC_COMM_SELF, PETSC_ERR_SYS, "System error closing socket");
     72:   }
     73:   PetscCall(PetscFree(vmatlab));
     74:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinarySetSkipHeader_C", NULL));
     75:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinaryGetSkipHeader_C", NULL));
     76:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerBinaryGetFlowControl_C", NULL));
     77:   PetscFunctionReturn(PETSC_SUCCESS);
     78: }

     80: /*@
     81:   PetscOpenSocket - handles connected to an open port where someone is waiting.

     83:   Input Parameters:
     84: + hostname - for example www.mcs.anl.gov
     85: - portnum  - for example 80

     87:   Output Parameter:
     88: . t - the socket number

     90:   Notes:
     91:   Use close() to close the socket connection

     93:   Use read() or `PetscHTTPRequest()` to read from the socket

     95:   Level: advanced

     97: .seealso: `PetscSocketListen()`, `PetscSocketEstablish()`, `PetscHTTPRequest()`, `PetscHTTPSConnect()`
     98: @*/
     99: PetscErrorCode PetscOpenSocket(const char hostname[], int portnum, int *t)
    100: {
    101:   struct sockaddr_in sa;
    102:   struct hostent    *hp;
    103:   int                s      = 0;
    104:   PetscBool          flg    = PETSC_TRUE;
    105:   static int         refcnt = 0;

    107:   PetscFunctionBegin;
    108:   if (!(hp = gethostbyname(hostname))) {
    109:     perror("SEND: error gethostbyname: ");
    110:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error open connection to %s", hostname);
    111:   }
    112:   PetscCall(PetscMemzero(&sa, sizeof(sa)));
    113:   PetscCall(PetscMemcpy(&sa.sin_addr, hp->h_addr_list[0], hp->h_length));

    115:   sa.sin_family = (unsigned char)hp->h_addrtype;
    116:   sa.sin_port   = htons((u_short)portnum);
    117:   while (flg) {
    118:     if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) {
    119:       perror("SEND: error socket");
    120:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error");
    121:     }
    122:     if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
    123: #if defined(PETSC_HAVE_WSAGETLASTERROR)
    124:       ierr = WSAGetLastError();
    125:       if (ierr == WSAEADDRINUSE) (*PetscErrorPrintf)("SEND: address is in use\n");
    126:       else if (ierr == WSAEALREADY) (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
    127:       else if (ierr == WSAEISCONN) {
    128:         (*PetscErrorPrintf)("SEND: socket already connected\n");
    129:         Sleep((unsigned)1);
    130:       } else if (ierr == WSAECONNREFUSED) {
    131:         /* (*PetscErrorPrintf)("SEND: forcefully rejected\n"); */
    132:         Sleep((unsigned)1);
    133:       } else {
    134:         perror(NULL);
    135:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error");
    136:       }
    137: #else
    138:       if (errno == EADDRINUSE) {
    139:         PetscErrorCode ierr = (*PetscErrorPrintf)("SEND: address is in use\n");
    140:         (void)ierr;
    141:       } else if (errno == EALREADY) {
    142:         PetscErrorCode ierr = (*PetscErrorPrintf)("SEND: socket is non-blocking \n");
    143:         (void)ierr;
    144:       } else if (errno == EISCONN) {
    145:         PetscErrorCode ierr = (*PetscErrorPrintf)("SEND: socket already connected\n");
    146:         (void)ierr;
    147:         sleep((unsigned)1);
    148:       } else if (errno == ECONNREFUSED) {
    149:         refcnt++;
    150:         PetscCheck(refcnt <= 5, PETSC_COMM_SELF, PETSC_ERR_SYS, "Connection refused by remote host %s port %d", hostname, portnum);
    151:         PetscCall(PetscInfo(NULL, "Connection refused in attaching socket, trying again\n"));
    152:         sleep((unsigned)1);
    153:       } else {
    154:         perror(NULL);
    155:         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "system error");
    156:       }
    157: #endif
    158:       flg = PETSC_TRUE;
    159: #if defined(PETSC_HAVE_CLOSESOCKET)
    160:       closesocket(s);
    161: #else
    162:       close(s);
    163: #endif
    164:     } else flg = PETSC_FALSE;
    165:   }
    166:   *t = s;
    167:   PetscFunctionReturn(PETSC_SUCCESS);
    168: }

    170: /*
    171:    PetscSocketEstablish - starts a listener on a socket

    173:    Input Parameter:
    174: .    portnumber - the port to wait at

    176:    Output Parameter:
    177: .     ss - the socket to be used with `PetscSocketListen()`

    179:     Level: advanced

    181: .seealso: `PetscSocketListen()`, `PetscOpenSocket()`
    182: */
    183: static PetscErrorCode PetscSocketEstablish(int portnum, int *ss)
    184: {
    185:   char               myname[PETSC_MAX_OPTION_NAME];
    186:   int                s;
    187:   struct sockaddr_in sa;
    188:   struct hostent    *hp;

    190:   PetscFunctionBegin;
    191:   PetscCall(PetscGetHostName(myname, sizeof(myname)));

    193:   PetscCall(PetscMemzero(&sa, sizeof(struct sockaddr_in)));

    195:   hp = gethostbyname(myname);
    196:   PetscCheck(hp, PETSC_COMM_SELF, PETSC_ERR_SYS, "Unable to get hostent information from system");

    198:   sa.sin_family = (unsigned char)hp->h_addrtype;
    199:   sa.sin_port   = htons((u_short)portnum);

    201:   PetscCheck((s = socket(AF_INET, SOCK_STREAM, 0)) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "Error running socket() command");
    202: #if defined(PETSC_HAVE_SO_REUSEADDR)
    203:   {
    204:     int optval = 1; /* Turn on the option */
    205:     int ret    = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval));
    206:     PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_LIB, "setsockopt() failed with error code %d", ret);
    207:   }
    208: #endif

    210:   while (bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
    211: #if defined(PETSC_HAVE_WSAGETLASTERROR)
    212:     ierr = WSAGetLastError();
    213:     if (ierr != WSAEADDRINUSE) {
    214: #else
    215:     if (errno != EADDRINUSE) {
    216: #endif
    217:       close(s);
    218:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SYS, "Error from bind()");
    219:     }
    220:   }
    221:   listen(s, 0);
    222:   *ss = s;
    223:   PetscFunctionReturn(PETSC_SUCCESS);
    224: }

    226: /*
    227:    PetscSocketListen - Listens at a socket created with `PetscSocketEstablish()`

    229:    Input Parameter:
    230: .    listenport - obtained with `PetscSocketEstablish()`

    232:    Output Parameter:
    233: .     t - pass this to read() to read what is passed to this connection

    235:     Level: advanced

    237: .seealso: `PetscSocketEstablish()`
    238: */
    239: static PetscErrorCode PetscSocketListen(int listenport, int *t)
    240: {
    241:   struct sockaddr_in isa;
    242: #if defined(PETSC_HAVE_ACCEPT_SIZE_T)
    243:   size_t i;
    244: #else
    245:   int i;
    246: #endif

    248:   PetscFunctionBegin;
    249:   /* wait for someone to try to connect */
    250:   i = sizeof(struct sockaddr_in);
    251:   PetscCheck((*t = accept(listenport, (struct sockaddr *)&isa, (socklen_t *)&i)) >= 0, PETSC_COMM_SELF, PETSC_ERR_SYS, "error from accept()");
    252:   PetscFunctionReturn(PETSC_SUCCESS);
    253: }

    255: // "Unknown section 'Environmental Variables'"
    256: // PetscClangLinter pragma disable: -fdoc-section-header-unknown
    257: /*@
    258:   PetscViewerSocketOpen - Opens a connection to a MATLAB or other socket based server.

    260:   Collective

    262:   Input Parameters:
    263: + comm    - the MPI communicator
    264: . machine - the machine the server is running on, use `NULL` for the local machine, use "server" to passively wait for
    265:              a connection from elsewhere
    266: - port    - the port to connect to, use `PETSC_DEFAULT` for the default

    268:   Output Parameter:
    269: . lab - a context to use when communicating with the server

    271:   Options Database Keys:
    272:    For use with  `PETSC_VIEWER_SOCKET_WORLD`, `PETSC_VIEWER_SOCKET_SELF`,
    273:    `PETSC_VIEWER_SOCKET_()` or if
    274:     `NULL` is passed for machine or PETSC_DEFAULT is passed for port
    275: + -viewer_socket_machine <machine> - the machine where the socket is available
    276: - -viewer_socket_port <port>       - the socket to connect to

    278:   Environmental variables:
    279: +   `PETSC_VIEWER_SOCKET_MACHINE` - machine name
    280: -   `PETSC_VIEWER_SOCKET_PORT` - portnumber

    282:   Level: intermediate

    284:   Notes:
    285:   Most users should employ the following commands to access the
    286:   MATLAB `PetscViewer`
    287: .vb

    289:     PetscViewerSocketOpen(MPI_Comm comm, char *machine,int port,PetscViewer &viewer)
    290:     MatView(Mat matrix,PetscViewer viewer)
    291: .ve
    292:   or
    293: .vb
    294:     PetscViewerSocketOpen(MPI_Comm comm,char *machine,int port,PetscViewer &viewer)
    295:     VecView(Vec vector,PetscViewer viewer)
    296: .ve

    298:   Currently the only socket client available is MATLAB, PETSc must be configured with --with-matlab for this client. See
    299:   src/dm/tests/ex12.c and ex12.m for an example of usage.

    301:   The socket viewer is in some sense a subclass of the binary viewer, to read and write to the socket
    302:   use `PetscViewerBinaryRead()`, `PetscViewerBinaryWrite()`, `PetscViewerBinarWriteStringArray()`, `PetscViewerBinaryGetDescriptor()`.

    304:   Use this for communicating with an interactive MATLAB session, see `PETSC_VIEWER_MATLAB_()` for writing output to a
    305:   .mat file. Use `PetscMatlabEngineCreate()` or `PETSC_MATLAB_ENGINE_()`, `PETSC_MATLAB_ENGINE_SELF`, or `PETSC_MATLAB_ENGINE_WORLD`
    306:   for communicating with a MATLAB Engine

    308: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PETSCVIEWERSOCKET`, `MatView()`, `VecView()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerSetType()`,
    309:           `PetscViewerSocketSetConnection()`, `PETSC_VIEWER_SOCKET_`, `PETSC_VIEWER_SOCKET_WORLD`,
    310:           `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`, `PetscViewerBinaryWriteStringArray()`,
    311:           `PetscBinaryViewerGetDescriptor()`, `PetscMatlabEngineCreate()`
    312: @*/
    313: PetscErrorCode PetscViewerSocketOpen(MPI_Comm comm, const char machine[], int port, PetscViewer *lab)
    314: {
    315:   PetscFunctionBegin;
    316:   PetscCall(PetscViewerCreate(comm, lab));
    317:   PetscCall(PetscViewerSetType(*lab, PETSCVIEWERSOCKET));
    318:   PetscCall(PetscViewerSocketSetConnection(*lab, machine, port));
    319:   PetscFunctionReturn(PETSC_SUCCESS);
    320: }

    322: static PetscErrorCode PetscViewerSetFromOptions_Socket(PetscViewer v, PetscOptionItems PetscOptionsObject)
    323: {
    324:   PetscInt  def = -1;
    325:   char      sdef[256];
    326:   PetscBool tflg;

    328:   PetscFunctionBegin;
    329:   /*
    330:        These options are not processed here, they are processed in PetscViewerSocketSetConnection(), they
    331:     are listed here for the GUI to display
    332:   */
    333:   PetscOptionsHeadBegin(PetscOptionsObject, "Socket PetscViewer Options");
    334:   PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_PORT", sdef, 16, &tflg));
    335:   if (tflg) {
    336:     PetscCall(PetscOptionsStringToInt(sdef, &def));
    337:   } else def = PETSCSOCKETDEFAULTPORT;
    338:   PetscCall(PetscOptionsInt("-viewer_socket_port", "Port number to use for socket", "PetscViewerSocketSetConnection", def, NULL, NULL));

    340:   PetscCall(PetscOptionsString("-viewer_socket_machine", "Machine to use for socket", "PetscViewerSocketSetConnection", sdef, NULL, sizeof(sdef), NULL));
    341:   PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_MACHINE", sdef, sizeof(sdef), &tflg));
    342:   if (!tflg) PetscCall(PetscGetHostName(sdef, sizeof(sdef)));
    343:   PetscOptionsHeadEnd();
    344:   PetscFunctionReturn(PETSC_SUCCESS);
    345: }

    347: static PetscErrorCode PetscViewerBinaryGetSkipHeader_Socket(PetscViewer viewer, PetscBool *skip)
    348: {
    349:   PetscViewer_Socket *vsocket = (PetscViewer_Socket *)viewer->data;

    351:   PetscFunctionBegin;
    352:   *skip = vsocket->skipheader;
    353:   PetscFunctionReturn(PETSC_SUCCESS);
    354: }

    356: static PetscErrorCode PetscViewerBinarySetSkipHeader_Socket(PetscViewer viewer, PetscBool skip)
    357: {
    358:   PetscViewer_Socket *vsocket = (PetscViewer_Socket *)viewer->data;

    360:   PetscFunctionBegin;
    361:   vsocket->skipheader = skip;
    362:   PetscFunctionReturn(PETSC_SUCCESS);
    363: }

    365: PETSC_INTERN PetscErrorCode PetscViewerBinaryGetFlowControl_Binary(PetscViewer, PetscInt *);

    367: /*MC
    368:    PETSCVIEWERSOCKET - A viewer that writes to a Unix socket

    370:   Level: beginner

    372: .seealso: [](sec_viewers), `PETSC_VIEWERBINARY`, `PetscViewerSocketOpen()`, `PetscViewerDrawOpen()`, `PETSC_VIEWER_DRAW_()`, `PETSC_VIEWER_DRAW_SELF`, `PETSC_VIEWER_DRAW_WORLD`,
    373:           `PetscViewerCreate()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PETSCVIEWERBINARY`, `PETSCVIEWERDRAW`,
    374:           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`,
    375:           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
    376: M*/

    378: PETSC_EXTERN PetscErrorCode PetscViewerCreate_Socket(PetscViewer v)
    379: {
    380:   PetscViewer_Socket *vmatlab;

    382:   PetscFunctionBegin;
    383:   PetscCall(PetscNew(&vmatlab));
    384:   vmatlab->port          = 0;
    385:   vmatlab->flowcontrol   = 256; /* same default as in PetscViewerCreate_Binary() */
    386:   v->data                = (void *)vmatlab;
    387:   v->ops->destroy        = PetscViewerDestroy_Socket;
    388:   v->ops->flush          = NULL;
    389:   v->ops->setfromoptions = PetscViewerSetFromOptions_Socket;

    391:   /* lie and say this is a binary viewer; then all the XXXView_Binary() methods will work correctly on it */
    392:   PetscCall(PetscObjectChangeTypeName((PetscObject)v, PETSCVIEWERBINARY));
    393:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetSkipHeader_C", PetscViewerBinarySetSkipHeader_Socket));
    394:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetSkipHeader_C", PetscViewerBinaryGetSkipHeader_Socket));
    395:   PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetFlowControl_C", PetscViewerBinaryGetFlowControl_Binary));
    396:   PetscFunctionReturn(PETSC_SUCCESS);
    397: }

    399: /*@
    400:   PetscViewerSocketSetConnection - Sets the machine and port that a PETSc socket
    401:   viewer is to use

    403:   Logically Collective

    405:   Input Parameters:
    406: + v       - viewer to connect
    407: . machine - host to connect to, use `NULL` for the local machine,use "server" to passively wait for
    408:              a connection from elsewhere
    409: - port    - the port on the machine one is connecting to, use `PETSC_DEFAULT` for default

    411:   Level: advanced

    413: .seealso: [](sec_viewers), `PETSCVIEWERMATLAB`, `PETSCVIEWERSOCKET`, `PetscViewerSocketOpen()`
    414: @*/
    415: PetscErrorCode PetscViewerSocketSetConnection(PetscViewer v, const char machine[], int port)
    416: {
    417:   PetscMPIInt         rank;
    418:   char                mach[256];
    419:   PetscBool           tflg;
    420:   PetscViewer_Socket *vmatlab;

    422:   PetscFunctionBegin;
    424:   if (machine) PetscAssertPointer(machine, 2);
    425:   vmatlab = (PetscViewer_Socket *)v->data;
    427:   if (port <= 0) {
    428:     char portn[16];
    429:     PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_PORT", portn, 16, &tflg));
    430:     if (tflg) {
    431:       PetscInt pport;
    432:       PetscCall(PetscOptionsStringToInt(portn, &pport));
    433:       PetscCall(PetscMPIIntCast(pport, &port));
    434:     } else port = PETSCSOCKETDEFAULTPORT;
    435:   }
    436:   if (!machine) {
    437:     PetscCall(PetscOptionsGetenv(PetscObjectComm((PetscObject)v), "PETSC_VIEWER_SOCKET_MACHINE", mach, sizeof(mach), &tflg));
    438:     if (!tflg) PetscCall(PetscGetHostName(mach, sizeof(mach)));
    439:   } else {
    440:     PetscCall(PetscStrncpy(mach, machine, sizeof(mach)));
    441:   }

    443:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)v), &rank));
    444:   if (rank == 0) {
    445:     PetscCall(PetscStrcmp(mach, "server", &tflg));
    446:     if (tflg) {
    447:       int listenport = 0;

    449:       PetscCall(PetscInfo(v, "Waiting for connection from socket process on port %d\n", port));
    450:       PetscCall(PetscSocketEstablish(port, &listenport));
    451:       PetscCall(PetscSocketListen(listenport, &vmatlab->port));
    452:       close(listenport);
    453:     } else {
    454:       PetscCall(PetscInfo(v, "Connecting to socket process on port %d machine %s\n", port, mach));
    455:       PetscCall(PetscOpenSocket(mach, port, &vmatlab->port));
    456:     }
    457:   }
    458:   PetscFunctionReturn(PETSC_SUCCESS);
    459: }

    461: /*
    462:     The variable Petsc_Viewer_Socket_keyval is used to indicate an MPI attribute that
    463:   is attached to a communicator, in this case the attribute is a PetscViewer.
    464: */
    465: PetscMPIInt Petsc_Viewer_Socket_keyval = MPI_KEYVAL_INVALID;

    467: /*@C
    468:    PETSC_VIEWER_SOCKET_ - Creates a socket viewer shared by all processors in a communicator.

    470:    Collective

    472:    Input Parameter:
    473: .  comm - the MPI communicator to share the  `PETSCVIEWERSOCKET` `PetscViewer`

    475:    Level: intermediate

    477:    Options Database Keys:
    478:    For use with the default `PETSC_VIEWER_SOCKET_WORLD` or if
    479:    `NULL` is passed for machine or `PETSC_DEFAULT` is passed for port
    480: +  -viewer_socket_machine <machine> - machine to connect to
    481: -  -viewer_socket_port <port> - port to connect to

    483:    Environmental variables:
    484: +  `PETSC_VIEWER_SOCKET_PORT` - portnumber
    485: -  `PETSC_VIEWER_SOCKET_MACHINE` - machine name

    487:    Notes:
    488:    This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it

    490:    Unlike almost all other PETSc routines, `PETSC_VIEWER_SOCKET_()` does not return
    491:    an error code, it returns `NULL` if it fails. The  `PETSCVIEWERSOCKET`  `PetscViewer` is usually used in the form `XXXView(XXX object, PETSC_VIEWER_SOCKET_(comm))`

    493:    Currently the only socket client available is MATLAB. See
    494:    src/dm/tests/ex12.c and ex12.m for an example of usage.

    496:    Connects to a waiting socket and stays connected until `PetscViewerDestroy()` is called.

    498:    Use this for communicating with an interactive MATLAB session, see `PETSC_VIEWER_MATLAB_()` for writing output to a
    499:    .mat file. Use `PetscMatlabEngineCreate()` or `PETSC_MATLAB_ENGINE_()`, `PETSC_MATLAB_ENGINE_SELF`, or `PETSC_MATLAB_ENGINE_WORLD`
    500:    for communicating with a MATLAB Engine

    502: .seealso: [](sec_viewers), `PETSCVIEWERMATLAB`, `PETSCVIEWERSOCKET`, `PETSC_VIEWER_SOCKET_WORLD`, `PETSC_VIEWER_SOCKET_SELF`, `PetscViewerSocketOpen()`, `PetscViewerCreate()`,
    503:           `PetscViewerSocketSetConnection()`, `PetscViewerDestroy()`, `PETSC_VIEWER_SOCKET_()`, `PetscViewerBinaryWrite()`, `PetscViewerBinaryRead()`,
    504:           `PetscViewerBinaryWriteStringArray()`, `PetscViewerBinaryGetDescriptor()`, `PETSC_VIEWER_MATLAB_()`
    505: @*/
    506: PetscViewer PETSC_VIEWER_SOCKET_(MPI_Comm comm)
    507: {
    508:   PetscBool   flg;
    509:   PetscViewer viewer;
    510:   MPI_Comm    ncomm;

    512:   PetscFunctionBegin;
    513:   PetscCallNull(PetscCommDuplicate(comm, &ncomm, NULL));
    514:   if (Petsc_Viewer_Socket_keyval == MPI_KEYVAL_INVALID) PetscCallMPINull(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Socket_keyval, NULL));
    515:   PetscCallMPINull(MPI_Comm_get_attr(ncomm, Petsc_Viewer_Socket_keyval, (void **)&viewer, (int *)&flg));
    516:   if (!flg) { /* PetscViewer not yet created */
    517:     PetscCallNull(PetscViewerSocketOpen(ncomm, NULL, 0, &viewer));
    518:     PetscCallNull(PetscObjectRegisterDestroy((PetscObject)viewer));
    519:     PetscCallMPINull(MPI_Comm_set_attr(ncomm, Petsc_Viewer_Socket_keyval, (void *)viewer));
    520:   }
    521:   PetscCallNull(PetscCommDestroy(&ncomm));
    522:   PetscFunctionReturn(viewer);
    523: }