Socket-based chat software under Linux

Source: Internet
Author: User
Tags stdin server port htons

Learn Linux socket programming recently. Look at UNP's book. By the way, a software similar to the simplest chat feature is written. The interface is written in Qt. Write it down and summarize it, assuming there is a problem. Welcome everyone to communicate with me.

Mode is C/s mode, server side waits for request. The client sends a request after it is sent. The connection is TCP not UDP, in fact the UDP implementation is simpler.


I. Environmental construction

I used Docker to set up a few virtual machines, the details of which can be found on the Web or before I write about Docker summary: Click to open the link

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

After the construction of Docker is the main first to see if the network is connected, assuming that the link to see the links. Firewall set up a bit.


Two. No interface code implementation:

This part of the code is the main reference UNP on the simple sample, there will certainly be bugs, due to the lack of consideration of the complex TCP environment, is simply the 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.

All right. I have the following interface code can not configure the UNP environment


Three. Add interface

I have abstracted several base classes. The main interface is 4, let's take a look at the interface:




The server side and client chat interface are the same. Server side I did a little bit of processing to deny connections to multiple customers. When a customer chats, the listening socket is closed.

Just learning Qt began to engage in 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 set Again"), 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;}


The server-side code will not be released. Basically, they are similar.

I uploaded all the code to CSDN, link: Click to open the link
QT5 is required for installation, video and file feature is 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 LANs can chat directly, and later found that it does not work, no permission to change the network routing NAT rules.

Future plans such as the following:

1. The QT interface is not used. direct command line.

2. Implement file transfer.

3. Discard the C/s architecture, make a server with public IP, two chat hosts connect to this service at the same time, the server forwards


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

The code is not difficult, but it is also daoteng. Reprint Please specify address: http://blog.csdn.net/u011353822/article/details/41246277

Socket-based chat software under Linux

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.