网络Socket

SOCKET socket(int af, int type, int protocol)

af 为地址族(Address Family),也就是 IP 地址类型,常用的有 AF_INET 和 AF_INET6。AF 是“Address Family”的简写,INET是“Inetnet”的简写。AF_INET 表示 IPv4 地址,例如 127.0.0.1;AF_INET6 表示 IPv6 地址,例如 1030::C9B4:FF12:48AA:1A2B。
返回值是socket的ID值,标识socket的唯一性,是一个整形数。

struct sockaddr_in{
sa_family_t sin_family; //地址族(Address Family),也就是地址类型
uint16_t sin_port; //16位的端口号
struct in_addr sin_addr; //32位IP地址
char sin_zero[8]; //不使用,一般用0填充
};

struct in_addr{
in_addr_t s_addr; //32位的IP地址
};

struct sockaddr{
sa_family_t sin_family; //地址族(Address Family),也就是地址类型
char sa_data[14]; //IP地址和端口号
};
结构体sockaddr和sockaddr_in等价,sockaddr_in包含详细的ip地址和端口号,所以sockaddr_in更加利于阅读和使用,编程的时候多使用它。

bind:
int bind(SOCKET sock, const struct sockaddr *addr, int addrlen)
将套接字和ip地址和端口绑定。

connect:
int connect(SOCKET sock, const struct sockaddr *serv_addr, int addrlen)
各参数和bind函数一样,区别在于,connect函数是client端用于和server端建立连接。

listen:
int listen(SOCKET sock, int backlog);
sock 为需要进入监听状态的套接字,backlog 为请求队列的最大长度。
所谓被动监听,是指当没有客户端请求时,套接字处于“睡眠”状态,只有当接收到客户端请求时,套接字才会被“唤醒”来响应请求。

accept:
SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen);
当套接字处于监听状态时,可以通过 accept() 函数来接收客户端请求。
它的参数与 listen() 和 connect() 是相同的:sock 为服务器端套接字,addr 为 sockaddr_in 结构体变量,addrlen 为参数 addr 的长度,可由 sizeof() 求得。

accept() 返回一个新的套接字来和客户端通信,addr 保存了客户端的IP地址和端口号,而 sock 是服务器端的套接字,大家注意区分。后面和客户端通信时,要使用这个新生成的套接字,而不是原来服务器端的套接字。
最后需要说明的是:listen() 只是让套接字进入监听状态,并没有真正接收客户端请求,listen() 后面的代码会继续执行,直到遇到 accept()。accept() 会阻塞程序执行(后面代码不能被执行),直到有新的请求到来。

int setsockopt( int socket, int level, int option_name,

const void *option_value, size_t option_len);

第一个参数socket是套接字描述符。第二个参数level是被设置的选项的级别,如果想要在套接字级别上设置选项,就必须把level设置为 SOL_SOCKET。 option_name指定准备设置的选项,option_name可以有哪些取值,这取决于level。  

         int reuse = -1 ;
         setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));  //防止关闭服务器后系统还没收回地址被占用

Linux系统提供了获取主机信息的函数,gethostbyname(),gethostbyaddr(),两者都会用到一个结构体,结构体信息如下:

struct hostent {

char *h_name; /* official name of host */

char **h_aliases; /* alias list */

int h_addrtype; /* host address type */

int h_length; /* length of address */

char **h_addr_list; /* list of addresses */

}

#define h_addr h_addr_list[0] /* for backward compatibility */

#include < stdio.h >
#include < netdb.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < arpa/inet.h >

int main(int argc, char *argv[])
{
struct hostent *p;
int i;

if (argc < 2) return -1; p = gethostbyname(argv[1]); printf("hostname %s\n", p->h_name);
printf(“address “);
for (i = 0; p->h_addr_list[i]; i++)
{
printf(“%s “, inet_ntoa(*(struct in_addr *)p->h_addr_list[i]));

}
printf(“\n”);

return 0;

}

传参调用,参数长选项

void print_usage(const char *program_name)
{
printf(“\n%s — 1.0.0(2018.11.4)\n”, program_name);
printf(” Usage: %s -p [-h ]\n”, program_name);
printf(” -p –port the server listen port\n”) ;
printf(” -h –help the server file how to use\n”);

return ;
}

int opt = -1 ;
int port = 0 ;

const char *short_opts = “p:h”;

const struct option long_opts[] ={

{“help”, no_argument, NULL, ‘h’},

{ “port”, required_argument, NULL, ‘p’},

{0, 0, 0, 0}
};

while ((opt= getopt_long(argc, argv, short_opts, long_opts,NULL)) != -1)
{
switch (opt)
{
case ‘p’:
port = atoi(optarg);
break ;

case ‘h’:
print_usage(argv[0]) ;
return 0;

}

}

if( !port )
{
print_usage(argv[0]);
return 0;

}

服务器:

#include <stdio.h>

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <getopt.h>
#include <stdlib.h>


#define BACKLOG  13
#define Sock_Port 9806
#define BUF_SIZE 1024

#define MSG_STR "Hello Client Welcome to Connect...!"

void print_usage(const char *program_name) 
{  
                printf("\n%s -- 1.0.0(2018.11.4)\n", program_name);  
                printf(" Usage: %s -p <server_port>  [-h <server_use_help>]\n", program_name);  
                printf("        -p --port       the server listen port\n") ;
                printf("        -h --help       the server file how to use\n");  


                return ;
}  


int main( int argc, char **argv )
{
        int listen_fd,client_fd = -1 ;
        struct sockaddr_in      serv_addr ;
        struct  sockaddr_in     cli_addr ;
        socklen_t               cli_addr_len ;
        int                     rv = -1 ;
        char                    buf[BUF_SIZE] ;
        int                     opt = -1 ;
        int                     port = 0 ;


const char *short_opts = "p:h";  


const struct option long_opts[] =       {  

                                                {"help", no_argument, NULL, 'h'},  

                                                { "port", required_argument, NULL, 'p'},  

                                               {0, 0, 0, 0}  
                                        };  


while ((opt= getopt_long(argc, argv, short_opts, long_opts,NULL)) != -1) 
        {
                switch (opt) 
                {
                        case 'p':
                                port = atoi(optarg);
                                break ;

                        case 'h':
                                print_usage(argv[0]) ;
                                return 0;


                }


        }

        if( !port )
        {
                print_usage(argv[0]);
                return 0;

        }

        listen_fd = socket(AF_INET, SOCK_STREAM, 0) ;
        if(listen_fd < 0)
        {
                printf("creat socket failure : %s \n", strerror(errno) ) ;
                return -1 ;

        }
        printf("creat socket suceeful, listen_fd descriptor[%d]\n", listen_fd) ;

        memset(&serv_addr, 0, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET ;
        serv_addr.sin_port = htons(port) ;
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY) ;
        memset(&cli_addr, 0, sizeof(serv_addr));


         int reuse = -1 ;
         setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

        if ( bind(listen_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) ) < 0 )
        {
                printf("socket bind failure : %s\n", strerror(errno) ) ;
                goto cleanup ;
        }


        if ( listen(listen_fd ,BACKLOG) < 0 )
        {
                printf("socket listen failure: %s\n", strerror(errno) ) ;
                goto cleanup ;
        }


        while(1)
        {
                printf("\n/*********************************************************************/\n") ;
                printf("Server Start Work, Server port:%d, And Waiting The Client Connect ...\n", port) ;
                client_fd = accept(listen_fd,(struct sockaddr*) &cli_addr, &cli_addr_len) ; 
                if(client_fd < 0)
                {
                        printf("accept failure: %s\n", strerror(errno)) ;
                        return -1 ;
                }
                printf("accept succeful, client [%s:%d] \n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port) ) ;

                memset(buf, 0, sizeof(buf)) ;

                rv = read (client_fd, buf, sizeof(buf)) ;
                if(rv < 0)
                {
                        printf("read from client failure: %s\n", strerror(errno)) ;
                        goto cleanup ;
                }

                if(rv == 0)
                {
                        printf("client connect failure!\n") ;
                        continue ;
                }

                printf("\n %d byte read from client : '%s' " ,rv, buf) ;


/*
                pid_t   pid ;
                pid = fork() ;
                if( pid < 0 )
                {
                        printf("Create fork failure:%s\n", strerror(errno)) ;
                        return 0 ;
                }
                if( pid > 0 )
                {

                         if (write(client_fd, MSG_STR, strlen(MSG_STR) ) < 0)
                        {
                                printf("write to client failed: %s\n", strerror(errno)) ;
                                close(client_fd) ;
                                continue ;
                        }


                }


                if(pid == 0)
                {
                          memset(buf, 0, sizeof(buf)) ;

                rv = read (client_fd, buf, sizeof(buf)) ;
                if(rv < 0)
                {
                        printf("read from client failure: %s\n", strerror(errno)) ;
                        goto cleanup ;
                }

                if(rv == 0)
                {
                        printf("client connect failure!\n") ;
                        continue ;
                }

                printf("\n %d byte read from client : '%s' " ,rv, buf) ;


                }


*/

                if (write(client_fd, MSG_STR, strlen(MSG_STR) ) < 0)
                {
                        printf("write to client failed: %s\n", strerror(errno)) ;
                        close(client_fd) ;
                        continue ;
                }


                sleep(2) ;

                close(client_fd) ;

        }

cleanup:
        close(listen_fd) ;
        close(client_fd) ;


        return 0 ;
}

客户端

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <stdlib.h>
#include <netdb.h>

#define BUF_SIZE        1024
#define MSG_STR "Hello Server, I connecting..."

void print_usage(const char *program_name)
{

        printf("\n%s -- 1.0.0(2018.11.4)\n", program_name);
                                        
        printf(" Usage:(1) %s -i <server_ip> -p <server_port>  [-h <server_use_help>]\n", program_name);
        printf("       (2) %s -n <server_hostname> -p <server_port>  [-h <server_use_help>]\n", program_name);

        printf("        -i --ip         the server ip_address you want to connect\n") ;
        printf("        -p --port       the server listen port you want to connect\n") ;
        printf("        -n --hostname   the server hostname you want to connect\n") ;
        printf("        -h --help       the client file how to use\n");
        printf("        Notice: If use hostname to connect Server ,Information get Segmentation fault, Please check out the hostname is ture you input!\n");

        return ;
}

int main(int argc, char** argv)
{
        int     conn_fd ;
        struct  sockaddr_in serv_addr ;
        char    buf[BUF_SIZE] ;
        int     rv = -1 ;
        int     opt = -1 ;
        int     port = 0 ;
        char*   ip = NULL ;
        char*   hostname = NULL;

        struct hostent *hostnp;


        const char *short_opts = "n:i:p:h";


        const struct option long_opts[] =       {
                                                        {"help", no_argument, NULL, 'h'},
                                                        {"hostname", required_argument,NULL,'n'},
                                                        {"port", required_argument, NULL, 'p'},
                                                        {"ip", required_argument, NULL, 'i'},
                                                        {0, 0, 0, 0},
                                                };


        while ((opt= getopt_long(argc, argv, short_opts, long_opts,NULL)) != -1)
                {
                       switch (opt)
                        {
                                case 'p':
                                        port = atoi(optarg);
                                        break ;
                                case 'i':
                                        ip = optarg ;
                                        break ;

                                case 'n':
                                        hostname = optarg ;
                                        break ;

                                case 'h':
                                        print_usage(argv[0]) ;
                                        return 0;

                        }

                 }

        if( ( ( !port) || (!hostname) ) && ( (!ip) || (!port) )  )
        {    
                print_usage(argv[0]);
                return 0;
        }

        memset(buf, 0, sizeof(buf)) ;

        if ( hostname )
        {
                hostnp = gethostbyname(hostname) ;
                printf("hostname %s\n", hostnp->h_name);

                ip = inet_ntoa( * (struct in_addr *)hostnp->h_addr );
                printf("addr:%s\n",ip) ;
        }


        conn_fd = socket( AF_INET, SOCK_STREAM, 0 ) ;

        if(conn_fd < 0)
        {
                printf("creat socket failure : %s\n", strerror(errno)) ;
                return -1 ;
        }

        printf("socket suceeful,connect file descriptor[%d]\n" ,conn_fd) ;

        memset(&serv_addr, 0, sizeof(serv_addr)) ;
        serv_addr.sin_port = htons(port) ;
        serv_addr.sin_family = AF_INET ;
        inet_aton(ip, &serv_addr.sin_addr);

        if( connect(conn_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0 )
        {
                printf("connect failure[%s:%d] : %s\n",  inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port), strerror(errno)) ;
                goto cleanup ;
        }
        printf("connect server[%s:%d] succeful!\n ",  inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port)) ;

        if(write(conn_fd, MSG_STR, strlen(MSG_STR)) < 0 )
        {
                printf("Write to server failed: %s\n", strerror(errno)) ;
                goto cleanup ;
        }

        sleep(1) ;

        memset(buf, 0, sizeof(buf)) ;
        rv = read(conn_fd, buf, sizeof(buf)) ;
        if(rv < 0)
        {
                printf("read from server failed: %s\n", strerror(errno)) ;
                goto cleanup ;

        }

        printf("read %d byte from server:' %s'\n", rv, buf) ;

cleanup:
        close(conn_fd) ;


        return 0 ;
}

PS:端口用花生壳内网穿透

猜你喜欢

转载自blog.csdn.net/caijiwyj/article/details/83928458