linux socket 详解

来源:互联网 发布:sencon美瞳 知乎 编辑:程序博客网 时间:2024/05/14 02:36

头文件: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;
}

原创粉丝点击