linux网络编程初探

 1.单客户端模式的程序       来源:《Linux程序设计》第4版 15.2节

/*----头文件与变量声明-----------------------------------------------------*/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    int sockfd;
    int len;
    struct sockaddr_in address;
    int result;
    char ch = 'A';

/*--为客户建立一个套接字----------------------------------------------------*/
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

/*--根据服务器的情况给套接字命名----------------------------------------------*/
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr("127.0.0.1");
    address.sin_port = htons(9734);
    len = sizeof(address);

/*--将我们的套接字连接到服务器的套接字------------------------------------------*/
    result = connect(sockfd, (struct sockaddr *)&address, len);
    if(result == -1){
        perror("oops: connection failed");
        exit(1);
    }

/*--现在就可以通过sockfd进行读写操作了-----------------------------------------*/
    write(sockfd, &ch, 1);
    read(sockfd, &ch, 1);
    printf("char from server = %c
", ch);
    close(sockfd);
    exit(0);
}
client.c
/*-头文件与变量声明--------------------------------------------------------*/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    int server_sockfd, client_sockfd;
    int server_len, client_len;
    struct sockaddr_in server_address;
    struct sockaddr_in client_address;

/*--删除以前的套接字,为服务器创建一个未命名的套接字-------------------------*/
    unlink("server_socket");
    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

/*------命名套接字-----------------------------------------------------------*/
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = htonl(INADDR_ANY);
    server_address.sin_port = htons(9734);
    server_len = sizeof(server_address);
    bind(server_sockfd, (struct sockaddr *)&server_address, server_len);

/*---创建一个连接队列,开始等待客户进行连接----------------------------------*/
    listen(server_sockfd, 5);
    while(1){
        char ch;

        printf("server waiting
");

/*------接受一个连接---------------------------------------------------------*/
        client_len = sizeof(client_address);
        client_sockfd = accept(server_sockfd,
            (struct sockaddr *)&client_address, &client_len);

/*----对client_sockfd套接字上的客户进行读写操作------------------------------*/
        read(client_sockfd, &ch, 1);
        ch++;
        write(client_sockfd, &ch, 1);
        close(client_sockfd);
    }
}
server.c

 0基础者请将程序拷出,对照下面注释查看

2.编写套接字通信程序的步骤

①socket:创建套接字
-------------------------------------------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
int socket(  int domain,
      int type,
      int protocol);

domain(套接字域)取值:
AF_UNIX:unix文件系统套接字
AF_INET:因特网套接字

type(套接字类型)取值:
SOCK_STREAM:TCP流套接字
SOCK_DGRAM:UDP数据报套接字

protocol取值:
0(默认协议)

 

②sockaddr_in/sockaddr_un:套接字初始化
-------------------------------------------------------------------------------------
#include <sys/un.h>
struct sockaddr_un {
sa_family_t  sun_family;  /*AF_UNIX*/
char       sun_path[]; /*pathname*/
}

---------------------------------
#include <netinet/in.h>
struct sockaddr_in {
short int         sin_family; /*AF_INET*/
unsigned short int  sin_port;   /*Port number*/
struct in_addr    sin_addr;   /*Internet address*/
}
其中IP地址结构in_addr被定义为:
struct in_addr {
unsigned long int s_addr;
};

 

③bind:命名套接字
-------------------------------------------------------------------------------------
#include <sys/socket.h>
int bind( int socket,
     const struct sockaddr *address,
     size_t address_len);

 

④listen:服务器创建套接字队列
-------------------------------------------------------------------------------------
#include <sys/socket.h>
int listen(int socket, int backlog)

backlog表示队列长度,队列中未处理连接数大于backlog值时,拒绝连接
listen函数成功时返回0,失败时返回-1

 

⑤accept:服务器接受连接
-------------------------------------------------------------------------------------
#include <sys/socket.h>
int accept(  int socket,
      struct sockaddr *address,
      size_t *address_len);

accept系统调用只有当有客户试图连接到由socket参数指定的套接字上时才返回。
accept函数将创建一个新套接字来与该客户进行通信,并返回新套接字的描述符。
当有未处理客户连接时,accept函数将返回一个新的套接字文件描述符。
当发生错误时, accept函数返回-1


若套接字队列中无未处理连接,accept将其阻塞(程序将暂停)直到有客户建立连接。
int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, O_NONBLOCK|flags);

 

⑥connect:客户端请求连接
-------------------------------------------------------------------------------------
#include <sys/socket.h>
int connect(      int socket,
        const struct sockaddr *address,
        size_t address_len);

将参数socket指定的套接字连接到参数address指定的服务器套接字,
address指向的结构长度有参数address_len指定。
参数socket指定的套接字必须是通过socket条用获得的一个有效的文件描述符。

connect成功时返回0,失败时返回-1。

如果连接不能立刻建立,connect调用将阻塞一段不确定的超时时间。
一旦这个超时时间到达,连接将被放弃,connect调用失败。

但如果connect调用被一个信号中断,blah, blah——

 

⑦close:关闭套接字
-------------------------------------------------------------------------------------
调用close函数终止服务器与客户端上套接字的连接,就如同底层文件描述符进行关闭一样。
连接的两端都关闭套接字。对服务器来说read调用返回0时关闭套接字。
但如果套接字是一个面向连接类型的,并设置了SOCK_LINGER选项,
close调用会在该套接字还有为传输数据时阻塞。

 

⑧主机字节序与网络字节序
-------------------------------------------------------------------------------------
例子:如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为
big-endian little-endian
0x0000 0x12 0xcd
0x0001 0x23 0xab
0x0002 0xab 0x34
0x0003 0xcd 0x12
x86系列CPU都是little-endian的字节序.
网络字节顺序是TCP/IP中规定好的一种数据表示格式,
它与具体的CPU类型、操作系统等无关,
从而可以保证数据在不同主机之间传输时能够被正确解释。
网络字节顺序采用big endian排序方式。

#include <netinet/in.h>
unsigned long int htonl(unsigned long int hostlong);
unsigned short int htons(unsigned short int hostshort);
unsigned long int ntohl(unsigned long int netlong);
unsigned short ing ntohs(unsigned short int ntohs);

htons 把unsigned short类型从主机序转换到网络序
htonl 把unsigned long 类型从主机序转换到网络序
ntohs 把unsigned short类型从网络序转换到主机序
ntohl 把unsigned long 类型从网络序转换到主机序

在使用little endian的系统中 这些函数会把字节序进行转换
在使用big endian类型的系统中 这些函数会定义成空宏

 

参考文献:

 1.《linux程序设计》第4版第15章

 2.http://www.cnblogs.com/jacktu/archive/2008/11/24/1339789.html

原文地址:https://www.cnblogs.com/xiashu/p/3553677.html