国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【TCP服務(wù)器的演變過程】編寫第一個TCP服務(wù)器:實(shí)現(xiàn)一對一的連接通信

這篇具有很好參考價值的文章主要介紹了【TCP服務(wù)器的演變過程】編寫第一個TCP服務(wù)器:實(shí)現(xiàn)一對一的連接通信。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

一、前言

手把手教你從0開始編寫TCP服務(wù)器程序,體驗(yàn)開局一塊磚,大廈全靠壘。

為了避免篇幅過長使讀者感到乏味,對【TCP服務(wù)器的開發(fā)】進(jìn)行分階段實(shí)現(xiàn),一步步進(jìn)行優(yōu)化升級。
【TCP服務(wù)器的演變過程】編寫第一個TCP服務(wù)器:實(shí)現(xiàn)一對一的連接通信,C/C++技術(shù)干貨,tcp/ip,服務(wù)器,網(wǎng)絡(luò)協(xié)議,網(wǎng)絡(luò),linux,udp,后端

二、需要使用到的API

2.1、socket()函數(shù)

函數(shù)原型:

#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain, int type, int protocol);

這個函數(shù)建立一個協(xié)議族、協(xié)議類型、協(xié)議編號的socket文件描述符。如果函數(shù)調(diào)用成功,會返回一個標(biāo)識這個套接字的文件描述符,失敗的時候返回-1并設(shè)置了errno。

domain參數(shù)值含義:

名稱 含義
PF_UNIX,PF_LOCAL 本地通信
AF_INET,PF_INET IPv4協(xié)議
PF_INET6 IPv6協(xié)議
PF_NETLINK 內(nèi)核用戶界面設(shè)備
PF_PACKET 底層包訪問

type參數(shù)值含義:

名稱 含義
SOCK_STREAM TCP連接,提供序列化的、可靠的、雙向連接的字節(jié)流。支持帶外數(shù)據(jù)傳輸
SOCK_DGRAM UDP連接
SOCK_SEQPACKET 序列化包,提供一個序列化的、可靠的、雙向的數(shù)據(jù)傳輸通道,數(shù)據(jù)長度定常。每次調(diào)用讀系統(tǒng)調(diào)用時數(shù)據(jù)需要將全部數(shù)據(jù)讀出
:SOCK_PACKET 專用類型
SOCK_RDM 提供可靠的數(shù)據(jù)報文,不保證數(shù)據(jù)有序
SOCK_RAW 提供原始網(wǎng)絡(luò)協(xié)議訪問

protocol參數(shù)含義:
通常某協(xié)議中只有一種特定類型,這樣protocol參數(shù)僅能設(shè)置為0;如果協(xié)議有多種特定的類型,就需要設(shè)置這個參數(shù)來選擇特定的類型。

2.2、bind()函數(shù)

函數(shù)原型:

#include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);

參數(shù)說明:

  • 第1個參數(shù)sockfd是用socket()函數(shù)創(chuàng)建的文件描述符。
  • 第2個參數(shù)my_addr是指向一個結(jié)構(gòu)為sockaddr參數(shù)的指針,sockaddr中包含了地址、端口和IP地址的信息。
  • 第3個參數(shù)addrlen是my_addr結(jié)構(gòu)的長度,可以設(shè)置成sizeof(struct sockaddr)。

bind()函數(shù)的返回值為0時表示綁定成功,-1表示綁定失敗并設(shè)置了errno。

2.3、listen()函數(shù)

函數(shù)原型:

#include<sys/socket.h>
int listen(int sockfd, int backlog);

參數(shù)說明:

  • 第1個參數(shù)sockfd是用socket()函數(shù)創(chuàng)建的文件描述符。
  • 第2個參數(shù)backlog規(guī)定了內(nèi)核應(yīng)該為相應(yīng)套接字排隊(duì)的最大連接個數(shù)。

2.4、accept()函數(shù)

函數(shù)原型:

#include<sys/types.h>
#include<sys/socket.h>
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);

參數(shù)說明:

  • sockefd:套接字描述符,該套接字在listen() 后監(jiān)聽連接。
  • addr:(可選)指針。指向一個緩沖區(qū),其中接收為通訊層所知的連接實(shí)體的地址。Addr參數(shù)的實(shí)際格式由套接口創(chuàng)建時所產(chǎn)生的地址族確定。
  • addrlen:(可選)指針。輸入?yún)?shù),配合addr一起使用,指向存有addr地址長度的整形數(shù)。

2.5、recv()函數(shù)

函數(shù)原型:

#include<sys/types.h>
#include<sys/socket.h>
int recv( int fd, char *buf, int len, int flags);

參數(shù)說明:

  • 第一個參數(shù)指定接收端套接字描述符;
  • 第二個參數(shù)指明一個緩沖區(qū),該緩沖區(qū)用來存放recv函數(shù)接收到的數(shù)據(jù);
  • 第三個參數(shù)指明buf的長度;
  • 第四個參數(shù)一般置0。

返回值:

  • 返回大于0的數(shù),表示介紹到的數(shù)據(jù)大小。
  • 返回0,表示連接斷開。
  • 返回-1,表示接受數(shù)據(jù)錯誤。

2.6、send()函數(shù)

函數(shù)原型:

#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

參數(shù)說明:

  • sockfd:向套接字中發(fā)送數(shù)據(jù)
  • buf:要發(fā)送的數(shù)據(jù)的首地址
  • len:要發(fā)送的數(shù)據(jù)的字節(jié)
  • int flags:設(shè)置為MSG_DONTWAITMSG 時 表示非阻塞,設(shè)置為0時 功能和write一樣。

返回值:成功返回實(shí)際發(fā)送的字節(jié)數(shù),失敗返回 -1并設(shè)置了errno。

2.7、strerror()函數(shù)

strerror()函數(shù)返回一個指向字符串的指針,該字符串描述參數(shù)errnum中傳遞的錯誤代碼,可能使用當(dāng)前語言環(huán)境的LC_MESSAGES部分來選擇適當(dāng)?shù)恼Z言。(例如,如果errnum為EINVAL,則返回的描述將為“無效參數(shù)”。)應(yīng)用程序不能修改此字符串,但可以通過隨后調(diào)用strerror()strerror_l()來修改。任何其他庫函數(shù),包括perror(),都不會修改此字符串。

函數(shù)原型:

#include <string.h>

char *strerror(int errnum);

int strerror_r(int errnum, char *buf, size_t buflen);
/* XSI-compliant */
char *strerror_r(int errnum, char *buf, size_t buflen);
/* GNU-specific */
char *strerror_l(int errnum, locale_t locale);

三、實(shí)現(xiàn)步驟

一對一服務(wù)器設(shè)計(jì):
【TCP服務(wù)器的演變過程】編寫第一個TCP服務(wù)器:實(shí)現(xiàn)一對一的連接通信,C/C++技術(shù)干貨,tcp/ip,服務(wù)器,網(wǎng)絡(luò)協(xié)議,網(wǎng)絡(luò),linux,udp,后端

(1)創(chuàng)建socket。

int listenfd=socket(AF_INET,SOCK_STREAM,0);
if(listenfd==-1){
    printf("errno = %d, %s\n",errno,strerror(errno));
    return SOCKET_CREATE_FAILED;
}

(2)綁定地址。

struct sockaddr_in server;
memset(&server,0,sizeof(server));

server.sin_family=AF_INET;
server.sin_addr.s_addr=htonl(INADDR_ANY);
server.sin_port=htons(LISTEN_PORT);

if(-1==bind(listenfd,(struct sockaddr*)&server,sizeof(server))){
    printf("errno = %d, %s\n",errno,strerror(errno));
    close(listenfd);
    return SOCKET_BIND_FAILED;
}

(3)設(shè)置監(jiān)聽。

if(-1==listen(listenfd,BLOCK_SIZE)){
   printf("errno = %d, %s\n",errno,strerror(errno));
   close(listenfd);
   return SOCKET_LISTEN_FAILED;
}

(4)接收連接。

struct sockaddr_in client;
memset(&client,0,sizeof(client));
socklen_t len=sizeof(client);
    
int clientfd=accept(listenfd,(struct sockaddr*)&client,&len);
if(clientfd==-1){
    printf("errno = %d, %s\n",errno,strerror(errno));
    close(listenfd);
    return SOCKET_ACCEPT_FAILED;
}

(5)接收數(shù)據(jù)。

char buf[BUFFER_LENGTH]={0};
ret=recv(clientfd,buf,BUFFER_LENGTH,0);
if(ret==0) {
     printf("connection dropped\n");

}
printf("recv --> %s\n",buf);

(6)發(fā)送數(shù)據(jù)。

if(-1==send(clientfd,buf,ret,0))
{
    printf("errno = %d, %s\n",errno,strerror(errno));
}

(7)關(guān)閉文件描述符。

close(clientfd);
close(listenfd);

四、完整代碼

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>

#include <errno.h>
#include <string.h>
#include <unistd.h>


#define LISTEN_PORT     8888
#define BLOCK_SIZE      10
#define BUFFER_LENGTH   1024

enum ERROR_CODE{
    SOCKET_CREATE_FAILED=-1,
    SOCKET_BIND_FAILED=-2,
    SOCKET_LISTEN_FAILED=-3,
    SOCKET_ACCEPT_FAILED=-4
};



int main(int argc,char **argv)
{
    // 1.
    int listenfd=socket(AF_INET,SOCK_STREAM,0);
    if(listenfd==-1){
        printf("errno = %d, %s\n",errno,strerror(errno));
        return SOCKET_CREATE_FAILED;
    }

    // 2.
    struct sockaddr_in server;
    memset(&server,0,sizeof(server));

    server.sin_family=AF_INET;
    server.sin_addr.s_addr=htonl(INADDR_ANY);
    server.sin_port=htons(LISTEN_PORT);

    if(-1==bind(listenfd,(struct sockaddr*)&server,sizeof(server))){
        printf("errno = %d, %s\n",errno,strerror(errno));
        close(listenfd);
        return SOCKET_BIND_FAILED;
    }

    // 3.
    if(-1==listen(listenfd,BLOCK_SIZE)){
        printf("errno = %d, %s\n",errno,strerror(errno));
        close(listenfd);
        return SOCKET_LISTEN_FAILED;
    }

    // 4.
    struct sockaddr_in client;
    memset(&client,0,sizeof(client));
    socklen_t len=sizeof(client);
    
    int clientfd=accept(listenfd,(struct sockaddr*)&client,&len);
    if(clientfd==-1){
        printf("errno = %d, %s\n",errno,strerror(errno));
        close(listenfd);
        return SOCKET_ACCEPT_FAILED;
    }

    printf("client fd = %d\n",clientfd);
    int ret=1;
    while(ret>0){
        // 5.
        char buf[BUFFER_LENGTH]={0};
        ret=recv(clientfd,buf,BUFFER_LENGTH,0);
        if(ret==0) {
            printf("connection dropped\n");
            break;

        }
        
        printf("recv --> %s\n",buf);
        if(-1==send(clientfd,buf,ret,0))
        {
            printf("errno = %d, %s\n",errno,strerror(errno));
        }
        
    }
    close(clientfd);
    close(listenfd);

    return 0;
}

編譯命令:

gcc -o server server.c

五、TCP客戶端

5.1、自己實(shí)現(xiàn)一個TCP客戶端

自己實(shí)現(xiàn)一個TCP客戶端連接TCP服務(wù)器的代碼:

#include <stdio.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <errno.h>
#include <string.h>

#include <unistd.h>
#include <stdlib.h>

#define BUFFER_LENGTH   1024

enum ERROR_CODE{
    SOCKET_CREATE_FAILED=-1,
    SOCKET_CONN_FAILED=-2,
    SOCKET_LISTEN_FAILED=-3,
    SOCKET_ACCEPT_FAILED=-4
};

int main(int argc,char** argv)
{
    if(argc<3)
    {
        printf("Please enter the server IP and port.");
        return 0;
    }
    printf("connect to %s, port=%s\n",argv[1],argv[2]);

    int connfd=socket(AF_INET,SOCK_STREAM,0);
    if(connfd==-1)
    {
        printf("errno = %d, %s\n",errno,strerror(errno));
        return SOCKET_CREATE_FAILED;

    }
    struct sockaddr_in serv;
    serv.sin_family=AF_INET;
    serv.sin_addr.s_addr=inet_addr(argv[1]);
    serv.sin_port=htons(atoi(argv[2]));
    socklen_t len=sizeof(serv);
    int rwfd=connect(connfd,(struct sockaddr*)&serv,len);
    if(rwfd==-1)
    {
        printf("errno = %d, %s\n",errno,strerror(errno));
        close(rwfd);
        return SOCKET_CONN_FAILED;
    }
    int ret=1;
    while(ret>0)
    {
        char buf[BUFFER_LENGTH]={0};
        printf("Please enter the string to send:\n");
        scanf("%s",buf);
        send(connfd,buf,strlen(buf),0);

        memset(buf,0,BUFFER_LENGTH);
        printf("recv:\n");
        ret=recv(connfd,buf,BUFFER_LENGTH,0);
        printf("%s\n",buf);
        
    }
    close(rwfd);
    return 0;
}

編譯:

gcc -o client client.c

5.2、Windows下可以使用NetAssist的網(wǎng)絡(luò)助手工具

【TCP服務(wù)器的演變過程】編寫第一個TCP服務(wù)器:實(shí)現(xiàn)一對一的連接通信,C/C++技術(shù)干貨,tcp/ip,服務(wù)器,網(wǎng)絡(luò)協(xié)議,網(wǎng)絡(luò),linux,udp,后端

下載地址:http://old.tpyboard.com/downloads/NetAssist.exe

小結(jié)

至此,我們實(shí)現(xiàn)了一個一對一的服務(wù)器連接,這階段的TCP服務(wù)器代碼只能接收一個客戶端接入,如果客戶端斷開了就會直接退出。重點(diǎn)是掌握開發(fā)TCP服務(wù)器的基本流程,下一章節(jié)將介紹在此基礎(chǔ)上進(jìn)行升級,實(shí)現(xiàn)可以接受多個客戶端的同時接入。
【TCP服務(wù)器的演變過程】編寫第一個TCP服務(wù)器:實(shí)現(xiàn)一對一的連接通信,C/C++技術(shù)干貨,tcp/ip,服務(wù)器,網(wǎng)絡(luò)協(xié)議,網(wǎng)絡(luò),linux,udp,后端文章來源地址http://www.zghlxwxcb.cn/news/detail-773513.html

到了這里,關(guān)于【TCP服務(wù)器的演變過程】編寫第一個TCP服務(wù)器:實(shí)現(xiàn)一對一的連接通信的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包