Socket-based chat software under Linux

Source: Internet
Author: User
Tags int size readable stdin server port htons

Recently learn Linux socket programming, see UNP that book, by the Way, write a similar to the simplest chat function software, the interface is written in Qt, write down summary, if there is a problem, welcome everyone and I exchange.

The mode is the C/S mode, the server waits for the request, and the client sends the request. The connection is TCP is not UDP, in fact, the implementation of UDP is more simple.


I. Environmental construction

I use Docker to build a few virtual machines, the specific way you can refer to the online or I wrote a summary of Docker: Click to open the link

Docker is also very lightweight, much faster than a typical virtual machine.

After the installation of Docker is the basic first look at whether the network is connected, if you do not connect to look at the link, firewall set up a bit.


Two. No interface code implementation:

This part of the code mainly refer to the simple example on the UNP, which will certainly have bugs, because the complex TCP environment is not considered, but the simple implementation of the first:

Server-side:

#include "unp.h" #include <stdio.h> #include <unistd.h>void Answer (file *fop, file *fip, int sockfd) {int    MAXFDP1, stdineof;    Fd_set RSet;    Char Buf[maxline];    int n;    stdineof = 0;    Fd_zero (&rset); for (;;)        {if (stdineof = = 0) fd_set (Fileno (FIP), &rset);        Fd_set (SOCKFD, &rset);        MAXFDP1 = Max (Fileno (FIP), SOCKFD) + 1;        Select (MAXFDP1, &rset, NULL, NULL, NULL);                if (Fd_isset (SOCKFD, &rset)) {/* socket is readable */if ((n = Read (SOCKFD, buf, MAXLINE)) = = 0) {     if (stdineof = = 1) return;            /* Normal termination */else Err_quit ("Client quit!");        } Write (Fileno (FOP), buf, N); if (Fd_isset (Fileno (FIP), &rset)) {/* input is readable */if ((n = Read (Fileno (FIP), buf, MAXL                INE)) = = 0) {stdineof = 1; Shutdown (SOCKFD, SHUT_WR);                /* Send FIN */FD_CLR (Fileno (FIP), &rset);            Continue        } writen (SOCKFD, buf, N);    }}}int Main (int argc, char **argv) {int listenfd, CONNFD;    pid_t Childpid;    Socklen_t Clilen;    struct sockaddr_in cliaddr, servaddr;    LISTENFD = Socket (af_inet, sock_stream, 0);    Bzero (&servaddr, sizeof (SERVADDR));    servaddr.sin_family = af_inet;    SERVADDR.SIN_ADDR.S_ADDR = htonl (Inaddr_any);    Servaddr.sin_port = htons (Serv_port);    Servaddr.sin_port = htons (50001);    Bind (LISTENFD, (SA *) &servaddr, sizeof (SERVADDR));    Listen (LISTENFD, Listenq); for (;;)        {Clilen = sizeof (CLIADDR);                if (CONNFD = Accept (LISTENFD, (SA *) &cliaddr, &clilen)) < 0) {if (errno = = eintr)       Continue        /* Back to for () */Else Err_sys ("Accept error");        }if ((Childpid = Fork ()) = = 0) {/* child process */Close (LISTENFD);            /* Close Listening socket */Answer (stdout, stdin, CONNFD);            printf ("End of one connect!\n");        Exit (0);          } Close (CONNFD); /* Parent Closes connected socket */}}


Client code:

#include "unp.h" const int SIZE = 1024;void Input (FILE *fp, int sockfd) {INTMAXFDP1, stdineof;fd_setrset;charbuf[maxline ];intn;stdineof = 0; Fd_zero (&rset); for (;;) {if (stdineof = = 0) fd_set (Fileno (FP), &rset); Fd_set (SOCKFD, &rset); MAXFDP1 = max (Fileno (FP), SOCKFD) + 1; Select (MAXFDP1, &rset, NULL, NULL, NULL), if (Fd_isset (SOCKFD, &rset)) {/* socket is readable */if ((n = Read (sock FD, BUF, MAXLINE)) = = 0) {if (stdineof = = 1) return;/* normal termination */elseerr_quit ("Str_cli:server terminated Premat Urely ");} Write (Fileno (stdout), buf, n);}  if (Fd_isset (Fileno (FP), &rset)) {/* input is readable */if ((n = Read (Fileno (FP), buf, MAXLINE) = = 0) {stdineof = 1; Shutdown (SOCKFD, SHUT_WR);/* Send FIN */FD_CLR (Fileno (FP), &rset); continue;} Writen (SOCKFD, buf, n);}}} int main (int argc, char **argv) {intsockfd;struct sockaddr_inservaddr;if (argc! = 3) err_quit ("Usage:tcpcli <ipaddress >::<Port> "); sockfd = Socket (af_inet, sock_stream, 0); Bzero (&servadDr, sizeof (SERVADDR)); servaddr.sin_family = Af_inet;servaddr.sin_port = Htons (atoi (argv[2)); Inet_pton (Af_inet, argv [1], &servaddr.sin_addr);    Connect (SOCKFD, (SA *) &servaddr, sizeof (SERVADDR)); struct sockaddr_in SS;    socklen_t len = sizeof (ss);    if (GetSockName (SOCKFD, (SA *) &ss, &len) < 0) return 0;  int clientport = Ntohs (Ss.sin_port);    Pay attention the Translate n<->pstr_cli (stdin, SOCKFD);/* Do it all */printf ("%d\n", ClientPort); Input (stdin, SOCKFD); exit (0);}



Vim a paste, this code format I was helpless ...

To run through this code, you have to configure the UNP environment. OK, I have the code below the interface can not configure the UNP environment


Three. Add interface

I abstracted a few base classes, the main interface is 4, first to look at the interface bar:




The server side and the client chat interface is the same, the server side I did a little processing, rejected the connection of multiple customers, when a customer chats, the listening socket is closed.

Just learning Qt started to interface, it is really disgusting.

Main code:

Client Login:

#include "clientstart.h" #include "chatclient.h" #include <iostream> #include <fstream> #include < Sstream>using namespace Std;    Clientstart::clientstart (Qwidget *parent): startbase (parent) {this->classname = "clientstart";    /*belong to First layout*/qlabel *labeloppositeip = new Qlabel ("Please enter server IP:");    Oppositeip = new Qlineedit;    Qlabel *labeloppositeport = new Qlabel ("Please enter Server port:");    Oppositeport = new Qlineedit;    Firstlayout->addwidget (LABELOPPOSITEIP, 2, 0, 1, 1);    Firstlayout->addwidget (OPPOSITEIP, 2, 1, 1, 4);    Firstlayout->addwidget (Labeloppositeport, 3, 0, 1, 1);    Firstlayout->addwidget (Oppositeport, 3, 1, 1, 4);    /*second layout*/secondlayout = new Qhboxlayout;    Secondlayout->setspacing (60);    Secondlayout->addwidget (buttonsure);    Secondlayout->addwidget (Buttoncancel);    Toplayout->addlayout (firstlayout);    Toplayout->addlayout (secondlayout);    qwidget* widget = new Qwidget (this); Widget->setlAyout (toplayout); This->setcentralwidget (widgets); Add the Toplayout in current Dialog}clientstart::~clientstart () {//delete this;}    void Clientstart::d oopen () {//qmessagebox::information (this, "Success", Qobject::tr ("xxx"), Qmessagebox::ok);    ServerIP = (Oppositeip->text ()). Tostdstring ();    ServerPort = (Oppositeport->text ()). Tostdstring ();    /*start Connect now*/bool Isconnect = Tryconnect ();        if (!isconnect) {Errorcall (this, "Connection failed");    return;    } chatclient cc (ClientIP, ClientPort, ServerIP, ServerPort, servaddr, CLIENTSOCKETFD);    Cc.exec ();    Cc.show (); This->close ();}    void Clientstart::d ocancel () {qmessagebox::information (this, "failed", QOBJECT::TR ("Please reset"), Qmessagebox::ok);    Oppositeip->settext (""); Oppositeport->settext ("");} BOOL Clientstart::tryconnect () {CLIENTSOCKETFD = socket (af_inet, sock_stream, 0); Bzero (&servaddr, sizeof (servaddr )); servaddr.sin_family = Af_inet;servaddr.sin_port = Htons (atoI (Serverport.c_str ())); Inet_pton (Af_inet, Serverip.c_str (), &servaddr.sin_addr); if (:: Connect (CLIENTSOCKETFD,    (SA *) &servaddr, sizeof (SERVADDR)) < 0) return 0;    /*get client port, IP has already got*/struct sockaddr_in SS;    socklen_t len = sizeof (ss);    if (GetSockName (CLIENTSOCKETFD, (SA *) &ss, &len) < 0) return 0; StringStream stmp;  change int to string stmp << Ntohs (ss.sin_port);    Pay attention the translate n<->p ClientPort = Stmp.str (); return 1;}

Client Chat:

#include "chatclient.h" #include <iostream> #include <fstream>using namespace std; Chatclient::chatclient (std::string clientip, std::string clientport, std::string ServerIP, std::string serverPort,    struct sockaddr_in servaddr, int clientsocketfd): Chatbase (NULL) {this->clientip = ClientIP;    This->clientport = ClientPort;    This->serverip = ServerIP;    This->serverport = ServerPort;    THIS-&GT;SERVADDR = servaddr;    THIS-&GT;CLIENTSOCKETFD = CLIENTSOCKETFD;    This->linelocalip->settext (QString (Clientip.c_str ()));    This->linelocalport->settext (QString (Clientport.c_str ()));    This->lineoppositeip->settext (QString (Serverip.c_str ()));         This->lineoppositeport->settext (QString (Serverport.c_str ()));    This->secondlayout->setreadonly (1);    This->secondlayout->settext ("Start chatting now!\n");    This->secondlayout->append (ShowTime ());    This->secondlayout->show (); /*connect the socket and function*/stdineof = 0;    Fd_zero (&rset);     REVSN = new Qsocketnotifier (CLIENTSOCKETFD, Qsocketnotifier::read); Qobject::connect (REVSN, SIGNAL (activated (int)), this, SLOT (dodatareceived ()));}    Chatclient::~chatclient () {stdineof = 1;        Shutdown (CLIENTSOCKETFD, SHUT_WR);/* Send FIN */Fd_zero (&rset); This->close ();}    void ChatClient::d osendmsg () {std::string sent = (Forthlayout->toplaintext ()). Tostdstring ();    Sent + = ' \ n ';        if (Write (CLIENTSOCKETFD, Sent.c_str (), Sent.size ()) < 0) {Errorcall (this, "Send Message failed!");    return;    } appendsecondlayout (Sent); Forthlayout->clear ();} void ChatClient::d ocancel () {forthlayout->clear ();}    void ChatClient::d osendfile () {}void chatclient::d ovedio () {}void chatclient::d odatareceived () {int revlen;            if ((Revlen = Read (CLIENTSOCKETFD, buf, MAXLINE)) = = 0) {if (stdineof = 1) return;/* normal termination */else { Errorcall (this, "server terminated prematurely");           This->close ();    }} Buf[revlen] = ' + ';    Appendsecondlayout (String (BUF)); return;}


Server-side code is not released, basically is similar.

I uploaded all the code to CSDN, link: Click to open the link
Installation requires configuration of QT5, video and file features are not implemented


Four. Summary and future prospects

This software is also written to play, there must be a bug. In fact, the previous plan is to make NAT forwarding, so that the host between the two LAN can chat directly, and later found that it does not work, no permission to modify the network routing NAT rules.

Future plans are as follows:

1. It is not the QT interface, direct command line.

2. Implement file transfer.

3. Abandon the C/s architecture, engage in a server with public IP, two chat hosts at the same time connect to this service, the server to forward


If you have any questions welcome communication, hope to have a small partner with me to do ~ ~.

Although the code is not difficult, but also oneself Daoteng, reprint please specify address: Http://write.blog.csdn.net/postedit

Socket-based chat software under Linux

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.