linux socket 詳解

來源:互聯網
上載者:User

標頭檔:sys/socket.h
相關結構體:
struct sockaddr
{
    unsigned short sa_family;   //地址族
    char sa_data[14];   //14位元組協議地址
};

struct sockaddr_in
{
    short int sin_family;   //地址族
    unsigned short int sin_port;   //連接埠號碼
    struct in_addr sin_addr;   //IP地址
    unsigned char sin_zero[8];   //填充0以保持與struct sockaddr同樣大小
};

 

struct in_addr

 {
   unsigned long s_addr; // that’s a 32-bit long, or 4 bytes
};
註:這兩個地址類型結構體在標頭檔中定義。

相關函數:

<開啟通訊端>
int socket(int af,int type,int protocol);   //返回socket通訊端,在後面的調用使用它。
af指定通訊發生地區(地址族)
UNIX系統有:AF_UNIX,AF_INET,AF_NS等。
DOS、WINDOWS中支援:AF_INET(網際網地區)
註:地址族與協議族相同。
type為SOCK_STREAM(建立TCP/IP串連的流式通訊端)或SOCK_DGRAM(建立不需連線的UDP資料通訊端)
註:進行資料報方式的資料轉送sendto()和recvfrom()時要用SOCK_DGRAM 不然會產生錯誤。
protocol通常為0

<指定本地地址>
int bind(int sockfd,struct sockaddr *my_addr,int addrlen);
sockfd為socket返回的通訊端。
my_addr指向包含本機IP地址和連接埠號碼等資訊的sockaddr類型指標。
addrlen通常為sizeof(struct sockaddr)
註:定義本機地址通常為
struct sockaddr_in my_addr;
... ...
my_addr.sin_family=AF_INET; 
my_addr.sin_port=htons(指定連接埠號碼);    //htons()進行位元組順序轉換,轉換成網路位元組優先順序。
my_addr.sin_addr.s_addr=INADDR_ANY;   //INADDR_ANY自動擷取本機IP地址

<監聽請求>
int listen(int sockfd,int backlog);
backlog指定在請求隊列中允許的最大請求數,進入隊列的請求將等待accept()它們。
註:伺服器程式的通常執行順序為 sockfd=socket( ... ... );   bind(sockfd, ..., ...);   listen(sockfd, ..., ...);
       用SOCK_STREAM模式需要 accept()串連請求。

<接受串連請求>
int accept(int sockfd,struct sockaddr * ob_addr,int *addrlen);    //返回一個新的通訊端,可以通過該通訊端與發出請求的用戶端進行資料轉送。
ob_addr為一個指向sockaddr類型指標,接受請求後,用戶端的地址資訊將儲存在*ob_addr中。
addrlen為指向int型的指標,*addrlen值為sizeof(struct sockaddr)。

<請求串連>
int connect(int sockfd,struct sockaddr * ob_addr,int addrlen);   //向目標地址發送串連請求。
*ob_addr為一個設定好的sockaddr類型目標地址。
註:通常
struct sockaddr_in ob_addr;
... ...
char ip[20]={"127.0.0.1"};
... ...
ob_addr.sin_family=AF_INET;
ob_addr.sin_addr.s_addr=inet_addr(ip);   //inet_addr()函數將名為ip的字串轉化為所需要的ip地址類型。
//相反的 inet_ntoa()函數可將這種類型轉化為字串類型。如:cout<<inet_ntoa(ob_addr.sin_addr);
ob_addr.sin_port=htons(目標連接埠號碼);   //必須對應伺服器監聽的指定連接埠,bind和connect中的端點地址必須一樣,用戶端自己的端點地址中連接埠號碼設定為0,意思是讓系統自動選擇連接埠號碼。

<SOCK_STREAM模式資料轉送>
int send(int sockfd,void * buf,int len,int flags);   //通過sockfd通訊端發送訊息
sockfd為串連上的某通訊端。
*buf為要傳輸的資料
len是資料長度(以位元組為單位)。
flags一般為0
int recv(int sockfd,void * buf,int len,int flags);   //通過sockfd通訊端接受訊息並存在*buf中

<SOCK_DGRAM模式資料轉送>
int sendto(int sockfd,void * buf,int len,int flags,struct sockaddr * ob_addr,int addrlen);
ob_addr為sockaddr類型的指標,指向設定好的目標地址。
addrlen常為sizeof(struct sockaddr)
int recvfrom(int sockfd,void *buf, int len,int flags,struct sockaddr * ob_addr,int addrlen);
ob_addr為一個指向sockaddr類型指標,接受資料後,發送端的地址資訊將儲存在*ob_addr中。

<關閉通訊端>
bool close(int sockfd);
註:用完了要關!

本文所用到的其他函數在netinet/in.h和arpa/inet.h中均可找到。

如果是在windows下,用VC寫socket程式,則標頭檔為winsock.h。其他函數基本相同。
可以參考:
《Windows Sockets 網路程式設計大全》蔣東興等編著 清華大學出版社

附:
//Linux 下socket通訊 伺服器端設計
#include <iostream>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string>

#define ListenNum 20
#define BufLen 1024

using namespace std;

int main()
{
    int sock,sock_new;
    int buf_len;
    socklen_t sin_size=sizeof(struct sockaddr);
    int re,se;
    char * buf_r=new char [BufLen];
    char * buf_s=new char [BufLen];
    struct sockaddr_in my_addr;
    struct sockaddr_in ob_addr;

    sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock==-1) {cout<<"socket error"<<endl;exit(0);}
    else {cout<<sock<<endl;}
    my_addr.sin_family=AF_INET; 
    my_addr.sin_port=htons(3490);
    my_addr.sin_addr.s_addr=INADDR_ANY;

    if(bind(sock,(struct sockaddr *)& my_addr,sizeof(struct sockaddr))<0)
    {
        cout<<"bind error"<<endl;
        exit(0);
    }
    cout<<"socket port: "<<ntohs(my_addr.sin_port)<<endl;
    if(listen(sock,ListenNum)<0)
    {
        cout<<"listen error"<<endl;
        exit(0);
    }
   
    while(1)
    {
        sock_new=accept(sock,(sockaddr *)&ob_addr,&sin_size);
        if(sock_new<0)
        {
            cout<<"accept error"<<endl;
            exit(0);
        }
        else
        {
            int p=fork();
            if(p==0)
            {
                cout<<"connect to :"<<inet_ntoa(ob_addr.sin_addr)<<" : "<<htons(ob_addr.sin_port)<<endl;
                int s=fork();
                if(s==0)
                {
                    do
                    {               
                        memset(buf_r,0,sizeof(buf_r));
                        re=recv(sock_new,buf_r,BufLen,0);

                        if(re==-1)
                        {
                            cout<<"recv error"<<endl;
                            exit(0);
                        }
                        else if(re==0)
                        {
                            cout<<inet_ntoa(ob_addr.sin_addr)<<"connection ended"<<endl;
                            close(sock_new);
                        }
                        else
                        {
                            cout<<inet_ntoa(ob_addr.sin_addr)<<" -> "<<buf_r<<endl;
                        }
                    }while(re>0);
                }
                else
                {
                    do
                    {
                        memset(buf_s,0,sizeof(buf_s));
                        cin.getline(buf_s,BufLen);
                        se=send(sock_new,buf_s,BufLen,0);
                        if(se==-1)
                        {
                            cout<<"send error"<<endl;
                            exit(0);
                        }
                        else
                        {
                            cout<<"sended!"<<endl;
                        }
                    }while(1);
                }
            }
        }
    }   
    close(sock);
    return 0;
}

//Linux 下socket通訊 用戶端設計
#include <iostream>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>

#define ListenNum 20
#define BufLen 1024

using namespace std;

int main()
{
   
    int sock,sock_new;
    int buf_len;
    socklen_t sin_size=sizeof(struct sockaddr);
    char * buf_s=new char [BufLen];
    char * buf_r=new char [BufLen];
    char * ip=new char [20];
    int re;
    memset(ip,0,sizeof(ip));
    struct sockaddr_in my_addr;
    struct sockaddr_in ob_addr;

    sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock==-1) {cout<<"socket error"<<endl;exit(0);}
    else {cout<<sock<<endl;}

    my_addr.sin_family=AF_INET; 
    my_addr.sin_port=htons(0);
    my_addr.sin_addr.s_addr=INADDR_ANY;

    if(bind(sock,(struct sockaddr *)& my_addr,sin_size)<0)
    {
        cout<<"bind error"<<endl;
        exit(0);
    }
   
    cout<<"socket port: "<<ntohs(my_addr.sin_port)<<endl;

    cout<<"input ip : ";
    cin.getline(ip,20);
   
    ob_addr.sin_family=AF_INET;
    ob_addr.sin_addr.s_addr=inet_addr(ip);
    ob_addr.sin_port=htons(3490);

    if(connect(sock,(sockaddr *)&ob_addr,sizeof(sockaddr))<0)
    {
        cout<<"connect error"<<endl;
        exit(0);
    }
    else
    {
        cout<<"connect success"<<endl;
        int p=fork();
        if(p==0)
        {
            while(cin.getline(buf_s,BufLen))
            {
                if(send(sock,buf_s,BufLen,0)!=-1)
                    cout<<"sended!"<<endl;
                else cout<<"send error"<<endl;
            }
        }
        else
        {
            do
            {
                memset(buf_r,0,sizeof(buf_r));
                re=recv(sock,buf_r,BufLen,0);
                if(re==-1)
                {
                    cout<<"recv error"<<endl;
                    exit(0);
                }
                else if(re==0)
                {
                    cout<<inet_ntoa(ob_addr.sin_addr)<<"connection ended"<<endl;
                    close(sock);
                }
                else
                {
                    cout<<inet_ntoa(ob_addr.sin_addr)<<" -> "<<buf_r<<endl;
                }
            }while(re>0);
        }
    }
    return 0;
}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.