• Linux 网络编程实例


      1 /*socket->bind->listen->accept->recv/recvfrom->send/sendto->close
      2 
      3   客户端:socket->connect->send/sendto->recv/recvfrom->close
      4 
      5   其中服务器端首先建立起socket,然后调用本地端口的绑定,接着就开始与客服端建立联系,并接收客户端发送的消息。
      6   客户端则在建立socket之后调用connect函数来建立连接。
      7 
      8   服务器端的源代码如下所示:*/
      9 
     10 /*"server.c"*/
     11 
     12 #include<sys/types.h>
     13 #include<sys/socket.h>
     14 #include<stdio.h>
     15 #include<stdlib.h>
     16 #include<errno.h>
     17 #include<string.h>
     18 #include<unistd.h>
     19 #include<netinet/in.h>
     20 
     21 #define PORT  3490    //端口
     22 
     23 #define BUFFER_SIZE  1024        //缓冲区大小
     24 
     25 #define MAX_QUE_CONN_NM  5    //服务器等待连接队列的最大长度。
     26 
     27 int main(){
     28 
     29     struct sockaddr_in server_sockaddr,client_sockaddr;     //分别定义服务器和客户端套接字
     30     int sin_size,recvbytes;
     31     int server_fd,client_fd;
     32     char buf[BUFFER_SIZE];            //缓冲区
     33 
     34     /*
     35        SOCKET PASCAL FAR socket( int af, int type, int protocol);
     36        af:一个地址描述。目前仅支持AF_INET格式,也就是说ARPA Internet地址格式。
     37        type:指定socket类型。新套接口的类型描述类型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。
     38        常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
     39        protocol:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。
     40        常用的协议有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,
     41        它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
     42      */
     43     if((server_fd = socket(AF_INET,SOCK_STREAM,0))== -1){  //建立socket连接www.linuxidc.com
     44         perror("create socket fail");
     45         exit(1);
     46     }
     47 
     48     printf("Socket id=%d
    ",server_fd);
     49 
     50     /*设置sockaddr_in结构体中的相关参数*/
     51 
     52     server_sockaddr.sin_family = AF_INET;
     53     server_sockaddr.sin_port = htons(PORT);   //由于在写网络程序时字节的网络顺序和主机顺序会有问题
     54     server_sockaddr.sin_addr.s_addr = INADDR_ANY;    //即0.0.0.0 任意地址
     55     bzero(&(server_sockaddr.sin_zero),8);
     56     int i = 1;  //允许重复使用本地地址与套接字进行绑定
     57 
     58     /*int PASCAL FAR setsockopt(SOCKET s,int level,int optname,const char FAR *optval,int optlen);
     59       s:标识一个套接字的描述符。
     60       level:选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。
     61       optname:需设置的选项。
     62       optval:指针,指向存放选项值的缓冲区。
     63       optlen:optval缓冲区长度。
     64      */
     65     setsockopt(server_fd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i));  
     66 
     67     /*
     68        int bind(SOCKET socket, const struct sockaddr *address,
     69        socklen_t address_len);
     70        参数说明:
     71        socket:是一个套接字。
     72        address:是一个sockaddr结构指针,该结构中包含了要结合的地址和端口号。
     73        address_len:确定address缓冲区的长度。
     74        返回值:如果函数执行成功,返回值为0,否则为SOCKET_ERROR。
     75      */
     76     if(bind(server_fd,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr)) == -1){  //绑定函数bind
     77         perror("bind fail");
     78         exit(1);
     79     }
     80 
     81     printf("Bind success!
    ");
     82 
     83     /*
     84        int PASCAL FAR listen( SOCKET s, int backlog);
     85        S:用于标识一个已捆绑未连接套接口的描述字。
     86        backlog:等待连接队列的最大长度。
     87      */
     88     if(listen(server_fd,MAX_QUE_CONN_NM)== -1){  //调用listen函数,创建为处理请求的队列
     89         perror("listen fail");
     90         exit(1);
     91     }
     92 
     93     printf("Listening......
    ");
     94 
     95     /*
     96        SOCKET PASCAL FAR accept( SOCKET s, struct sockaddr FAR* addr,int FAR* addrlen);
     97        s:套接口描述字,该套接口在listen()后监听连接。
     98        addr:(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。Addr参数的实际格式由套接口创建时所产生的地址族确定。
     99        addrlen:(可选)指针,输入参数,配合addr一起使用,指向存有addr地址长度的整型数。
    100      */
    101     if((client_fd = accept(server_fd,(struct sockaddr *)&client_sockaddr,&sin_size))==-1){//调用accept函数,等待客户端的接
    102         perror("accept fail");
    103         exit(1);
    104     }
    105 
    106     printf("server: got connection from %s 
    ",inet_ntoa(client_sockaddr.sin_addr));
    107 
    108     memset(buf,0,sizeof(buf));
    109     /*
    110        int PASCAL FAR recv( SOCKET s, char FAR* buf, int len, int flags);
    111        s:一个标识已连接套接口的描述字。
    112        buf:用于接收数据的缓冲区。
    113        len:缓冲区长度。
    114        flags:指定调用方式。通常写成0
    115      */
    116     if((recvbytes = recv(client_fd,buf,BUFFER_SIZE,0)) == -1){//调用recv函数接收客户端的请求
    117         perror("recv fail");
    118         exit(1);
    119     }
    120     
    121     printf("Received a message: %s
    ",buf);
    122     
    123 
    124     /*向客户起写数据*/        
    125     if(write(client_fd,"客户端我收到你发来的数据了,你能收到这句应答吗?
    ",1024)==-1)
    126         perror("write error!");        
    127     
    128     close(client_fd);
    129 
    130     close(server_fd);
    131     exit(0);
    132 }
    133 
    134 
    135 
    136 
    137 
    138 /*客户端*/
    139 /*client.c  运行方式:./client localhost*/
    140 #include <stdio.h>
    141 #include <stdlib.h>
    142 #include <errno.h>
    143 #include <string.h>
    144 #include <netdb.h>
    145 #include <sys/types.h>
    146 #include <netinet/in.h>
    147 #include <sys/socket.h>
    148 #define PORT 3490
    149 #define MAXDATASIZE 5000
    150 int main(int argc,char **argv)
    151 {
    152     int sockfd,nbytes;
    153     char buf[1024];
    154     struct hostent *he;
    155     struct sockaddr_in srvaddr;
    156     if(argc!=2)
    157     {
    158         perror("Usage:client hostname
    ");
    159         exit(1);
    160     }
    161     /*函数gethostbyname获得指定域名地址所对应的ip地址*/
    162     if((he=gethostbyname(argv[1]))==NULL)
    163     {
    164         perror("gethostbyname");
    165         exit(1);
    166     }
    167     /*创建套接字,返回套接字描述符*/
    168     if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
    169     {
    170         perror("create socket error");
    171         exit(1);
    172     }
    173     bzero(&srvaddr,sizeof(srvaddr));
    174     /*用获得的远程服务器进程的ip地址和端口号来填充一个internet套接字地址结构*/
    175     srvaddr.sin_family=AF_INET;
    176     srvaddr.sin_port=htons(PORT);
    177     srvaddr.sin_addr=*((struct in_addr *)he->h_addr);
    178     /*用connect于这个远程服务器建立一个internet连接*/
    179     if(connect(sockfd,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr))==-1)
    180     {
    181         perror("connect error");
    182         exit(1);
    183     }
    184     
    185     
    186     if((send(sockfd,"客户端向服务端发送数据,服务端你收到了吗?",1024,0)) == -1)
    187     {
    188         perror("send error");
    189         exit(1);
    190     }
    191     
    192 
    193     
    194     /*调用read函数读取服务器write过来的信息*/
    195     if((nbytes=read(sockfd,buf,MAXDATASIZE))==-1)
    196     {
    197         perror("read error");
    198         exit(1);
    199     }
    200     buf[nbytes]='';
    201     printf("read: %s",buf);
    202     close(sockfd);
    203 }
    View Code

    运行方式: gcc -o service service.c

          gcc -o client client.c

         chmod +x service

          chmod +x client

    在一个终端运行:./service

    在另一个终端运行:./client localhost

    服务端输出:

    Socket id=3 Bind success! Listening...... server: got connection from 127.0.0.1 Received a message: 客户端向服务端发送数据,服务端你收到了吗?

    客户端输出:

    read: 客户端我收到你发来的数据了,你能收到这句应答吗?

  • 相关阅读:
    RDIFramework.NET ━ .NET快速信息化系统开发框架钜献 V2.9 版本震撼发布
    免费的海量编程中文书籍索引-都是干货【强烈建议收藏】
    SQLServer2005+附加数据库时出错提示操作系统错误5(拒绝访问)错误5120的解决办法
    实例演示使用RDIFramework.NET 框架的工作流组件进行业务流程的定义—请假申请流程-Web
    RDIFramework.NET 框架之组织机构权限设置
    实例演示使用RDIFramework.NET 框架的工作流组件进行业务流程的定义—请假申请流程-WinForm
    RDIFramework.NET ━ 9.16 案例模块━ Web部分
    RDIFramework.NET ━ 9.15 个性化设置 ━ Web部分
    RDIFramework.NET ━ 9.14 数据库连接管理 ━ Web部分
    RDIFramework.NET ━ 9.13 系统日志与系统异常管理 ━ Web部分
  • 原文地址:https://www.cnblogs.com/bpdwn/p/3399712.html
Copyright © 2020-2023  润新知