Linux下的TCP Socket通信


一、socket函數

1、頭文件:

#include <sys/types.h> /* See NOTES */

#include <sys/socket.h>

2、函數原型:

int socket(int domain, int type, int protocol);

socket函數類似於open,用來打開一個網絡連接,如果成功則返回一個網絡文件描述符(int類型),之后我們操作這個網絡連接都通過這個網絡文件描述符。

dimain:域,網絡域,網絡地址范圍(IPV4或IPV6等),也就是協議簇

type:指定套接字類型:SOCK_STREAM(TCP網絡)、SOCK_DGRAM(UDP)、SOCK_SEQPACKET

protocol:指定協議,如果指定0,表示使用默認的協議

3、函數形參:

3.1、domain:(域)

AF_INET      ip
AF_INET6    ipv6

AF_PACKET         packet         低級數據包接口

PF_PACKET   不懂,待了解

PF_INET      待了解(AF開頭的表示地址族,PF開頭的表示協議族,協議族包含多個地址族,但是當前這種還從未實現,而在<sys/socket.h>中PF的值總是與AF的值相等的)

3.2、type:(套接字類型):

SOCK_RAW      原始套接字     ——>使用原始套接字時候調用,原始套接字也就是鏈路層協議

SOCK_STREAM    字節流套接字    ——>提供順序,可靠,雙向,基於連接的字節流。 可以支持帶外數據傳輸機制。例如:TCP協議、FTP協議

SOCK_DGRAM         數據報套接字    ——>支持數據報(無連接,不可靠的固定最大長度的消息)例如:UDP協議

SOCK_SEQPACKET   有序分組套接字    ——>為固定最大長度的數據報提供有序,可靠,雙向連接的數據傳輸路徑; 消費者需要利用每個輸入系統調用讀取整個分組

3.3、protocol(協議):

IPPROTO_IP       IP傳輸協議

IPPROTO_TCP      TCP傳輸協議

IPPROTO_UDP       UDP協議

IPPROTO_SCTP      SCTP傳輸協議

IPPROTO_ICMP          ICMP協議

IPPROTO_IGMP      IGMP協議

一般情況下IPPROTO_TCP、IPPROTO_UDP、IPPROTO_ICMP協議用的最多,UDP協議protocol就取IPPROTO_UDP,TCP協議protocol就取IPPROTO_TCP;一般情況下,我們讓protocol等於0就可以,系統會給它默認的協議。但是要是使用raw socket協議,protocol就不能簡單設為0,要與type參數匹配.

4、返回值:

成功時返回一個小的非負整數值,他與文件描述符類似,我們稱為套接字描述符,簡稱sockfd。失敗,則返回-1。

5、例子:

/*---------------------創建一個監聽socket-------------------*/

    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

    {

        perror("socket() error\n");

        exit(1);

}

二、bind函數

1、頭文件:

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>

2、函數原型:

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

服務端套接字綁定自己的IP地址與端口號,客戶端那邊可以不寫,內核會給它分配一個臨時的端口。

3、函數形參:

3.1、sockfd:服務器或者客戶端自己創建的socket

3.2、addr:服務器或者客戶端自己的地址信息(協議族、IP、端口號)

3.3、addrlen:服務器或者客戶端自己的地址信息的長度

4、返回值:

綁定成功,返回0,失敗返回-1

5、例子:

    /*---------------------綁定IP和端口bind----------------------*/

    bzero(&server, sizeof(server));

    server.sin_family = AF_INET;

    server.sin_port = htons(port);

    server.sin_addr.s_addr = inet_addr(ip);

 

    if (bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1)

    {

        perror("bind() error\n");

        exit(1);

    }

三、connect函數

1、頭文件:

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>

2、函數原型:

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

TCP客戶端通過connect函數與服務端連接,進行通信。

3、函數形參:

3.1、sockfd(客戶端自己創建的sock)

3.2、addr(服務端地址族、服務端IP地址、服務端端口號)

3.3、addrlen(服務端地址字節長度)

4、返回值:

連接成功,返回0,連接失敗,返回-1

5、例子:

struct sockaddr_in client;

addrlen = sizeof(client);

        if ((connetfd = accept(listenfd, (struct sockaddr *)&client, &addrlen)) == -1)

        {

            perror("accept() error\n");

            exit(1);

        }

接下來給出一個大例子,tcp——socket套接字通信,結合sqlite3數據庫操作

#include <stdio.h>

#include <stdlib.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <unistd.h>

#include <string.h>

 

int main()

{

    struct sockaddr_in server;

    struct sockaddr_in client;

    int listenfd, connetfd;

    char ip[20];

    int port;

    int addrlen;

    char rebuf[100];

    char wrbuf[100];

    char tmp[100];

    int revlen;

    /*---------------------創建一個監聽socket-------------------*/

    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

    {

        perror("socket() error\n");

        exit(1);

    }

 

    /*----------------------輸入要監聽的IP和端口----------------------*/

    printf("Please input the ip:\n");

    scanf("%s", ip);

    printf("Please input the port:\n");

    scanf("%d", &port);

 

    /*---------------------綁定IP和端口bind----------------------*/

    bzero(&server, sizeof(server));

    server.sin_family = AF_INET;

    server.sin_port = htons(port);

    server.sin_addr.s_addr = inet_addr(ip);

 

    if (bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1)

    {

        perror("bind() error\n");

        exit(1);

    }

    /*----------------------開始監聽listen-------------------*/

    if (listen(listenfd, 20) == -1)

    {

        perror("listen() error\n");

        exit(1);

    }

    int client_pid = 0;

    while (1)

    {

        /*----------------------accept------------------*/

        addrlen = sizeof(client);

        if ((connetfd = accept(listenfd, (struct sockaddr *)&client, &addrlen)) == -1)

        {

            perror("accept() error\n");

            exit(1);

        }

        /*---------------------show client---------------*/

        printf("connect successful!\n");

        printf("the client ip is %s,port is %d\n", inet_ntoa(client.sin_addr), ntohs(port));

        client_pid = fork();

        if (client_pid == 0)

        {

            //子進程

            close(listenfd); //關閉監聽請求

            /*----------------------read and write----------*/

            int serial = 0;

            while (1)

            {

                bzero(rebuf, sizeof(rebuf));

                revlen = read(connetfd, rebuf, sizeof(rebuf));

                if ((memcmp("bye", rebuf, 3)) == 0)

                {

                    printf("Bye-bye then close the connect...\n");

                    break;

                }

                bzero(wrbuf, sizeof(wrbuf));

                bzero(tmp, sizeof(tmp));

                sprintf(tmp, "%d", serial);

                strcat(tmp, rebuf);

                bcopy(tmp, wrbuf, strlen(tmp));

                write(connetfd, wrbuf, sizeof(wrbuf));

                rebuf[revlen] = '\0';

                printf("the info from client is:%s\n", rebuf);

                serial++;

            }

            return 0;

        }

        close(connetfd); //父進程關閉連接請求

    }

    return 0;

}

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM