linux socke编程实例:一个简单的echo服务器程序

    也许是第一次真正使用linux操作系统,忽然对丢弃已久的C产生了很大的兴趣,最近想学点linux的知识,在linux的世界里面,接触得最多的还是C,故有感写一下linux的socket程序。
    也许很多朋友会像我一样,这样的程序在Java写得太多,以至对Socket的通信细节还不曾忘怀。由于未有linux下
编程经验,在写程序过程中碰到很多不懂的东西,经过google一翻后,终于把一些基本的东西搞懂了。好了,闲话少讲,下面说说编程的想法。
    本文编的是echo服务器示例程序,当收到客户端的数据,服务器把数据不经加工地发送给客户。采用TCP连接,采用端口8080进行设计,在整个过程中主要涉及socket的通信。

首先建立一个 socket,代码如下:
int socketfd;
socketfd 
= socket(AF_INET, SOCK_STREAM, 0);

 socket函数是我们写socket程序遇到的第一个函数,它在指定的协议上创建一个socket,它的函数说明如下所示:

#include <sys/socket.h>
int socket ( int AddressFamily,  int Type, int  Protocol)


其中:AddressFamily参数指定socket操作中所要解释的网络地址类型,值为如下之一:

AF_UNIX
表示操作系统文件路径
AF_INET
表示Internet网络地址
AF_NS
表示XEROX网络地址
Type参数表明了通信的语义,即通信连接的方式。参数为如下之一:
SOCK_STREAM
提供稳定可靠的连接,并且是双向的通信方式,如TCP。
SOCK_DGRAM
提供无连接的数据报通信,如UDP。
SOCK_RAW
提供该问内部网络协议和网络接口, 只有root用户才可以使用些协议。

返回值:成功则返socket描述符,出错则返回-1,可通过errno代码进行查看错误原因。


再次,把socket绑定到本机上,代码如下:
    struct  sockaddr_in sa;
    bzero(
& sa,  sizeof (sa));
    sa.sin_family 
=  AF_INET;
    sa.sin_port 
=  htons(EHCO_PORT);
    sa.sin_addr.s_addr 
=  htons(INADDR_ANY);
    bzero(
& (sa.sin_zero),  8 );

    
if (bind(socketfd, ( struct  sockaddr  * ) & sa,  sizeof (sa)) !=   0 )
    {
        printf(
" bind failed " );
        printf(
" errno=%d " , errno);
        exit(
1 );
    }
    
else
    {
        printf(
" bind successfully " );
    }

上面的代码中,定义一个scokaddr_in 结构体变量sa,然后填机服务所要开通的端口号和地址。
 sa.sin_family = AF_INET;
 >表明地址类型
 sa.sin_port 
= htons(EHCO_PORT);
>端口号为8080
    sa.sin_addr.s_addr 
= htons(INADDR_ANY);
 >表明绑定在本机

  然后利用bind函数,把刚才已建立的socket作为参数,绑定起来。

绑定完成后,服务器要侦听客户端的连接,因此首先要完成侦听设置这一过程,由listen函数实现,代码如下:
if(listen(socketfd ,MAX_CLIENT_NUM) != 0)
    
{
        printf(
"listen error ");
        exit(
1);
    }

    
else
    
{
        printf(
"listen successfully ");
    }

 listen(socketfd, MAX_CLIENT_NUM)表明在socketfd上侦听,其中客户个数最大值为MAX_CLIENT_NUM。

完成侦听后,可以让客户与服务器进行连接了。服务想获得客户的请求,则需要通过 accept函数来获得。同时,需要采用一个sockaddr_in结构体来获得客户的信息。代码如下:
    int  clientfd;  
    
struct  sockaddr_in clientAdd;
    
char  buff[ 101 ];
    socklen_t len 
=   sizeof (clientAdd);
    
int  closing  = 0 ;
    
while ( closing  ==   0    &&  (clientfd  =  accept(socketfd, ( struct  sockaddr  * ) & clientAdd,  & len))  > 0  )
    {
        
int  n;
        
while ((n  =  recv(clientfd,buff,  100 , 0  ))  >   0 )
        {
            printf(
" number of receive bytes = %d " , n);
            write(STDOUT_FILENO, buff, n);
            send(clientfd, buff, n, 
0 );
            buff[n] 
=   ' ' ;
            
if (strcmp(buff,  " quit " ==   0 )
            {
                
break ;
            }
            
else   if (strcmp(buff,  " close " ==   0 )
            {
                
// server closing
                closing  =   1 ;
                printf(
" server is closing " );
                
break ;
            }
        }

        close(clientfd);
    }

其中clientfd为客户的socket,在服务器端,每接受一个客户连接,都会返回一个客户的socket描述符,服务器根据它与客户进行通信。clientAdd为客户地址信息的结构体,在accept函数中完成对它的填充,可依此得到客户的地址信息。

 while( closing == 0  && (clientfd = accept(socketfd, (struct sockaddr *)&clientAdd, &len)) >0 )
等待第一个客户,当第一个客户的请求来到服务器后,该函数会返回,clientfd为客户的socket描述符。
接着进行通信
 while((n = recv(clientfd,buff, 100,0 )) > 0)
等待客户的数据,收到数据后,在标准输入出显示接收的数据信息,并把它发送回给客户:send(clientfd, buff, n, 0);
在这里,我们采用简单的命令对通信进行控制,quit表示客户要结束通信过程,而 close表示客户请求关闭服务器。关闭只需使用 close函数即可完成。

下面是完整的代码:
#include  < netdb.h >
#include 
< sys / socket.h >
#include 
< errno.h >
#include 
< stdio.h >
#include 
< unistd.h >

#define  EHCO_PORT    8080
#define  MAX_CLIENT_NUM        10

int  main()
{
    
int  socketfd;
    socketfd 
=  socket(AF_INET, SOCK_STREAM,  0 );
       
    
if (socketfd  ==   - 1 )
    {
        printf(
" errno=%d " , errno);
        exit(
1 );
    }
    
else
    {
        printf(
" socket create successfully " );
    }

    
struct  sockaddr_in sa;
    bzero(
& sa,  sizeof (sa));
    sa.sin_family 
=  AF_INET;
    sa.sin_port 
=  htons(EHCO_PORT);
    sa.sin_addr.s_addr 
=  htons(INADDR_ANY);
    bzero(
& (sa.sin_zero),  8 );

    
if (bind(socketfd, ( struct  sockaddr  * ) & sa,  sizeof (sa)) !=   0 )
    {
        printf(
" bind failed " );
        printf(
" errno=%d " , errno);
        exit(
1 );
    }
    
else
    {
        printf(
" bind successfully " );
    }

    
// listen
     if (listen(socketfd ,MAX_CLIENT_NUM)  !=   0 )
    {
        printf(
" listen error " );
        exit(
1 );
    }
    
else
    {
        printf(
" listen successfully " );
    }

    
int  clientfd;
    
struct  sockaddr_in clientAdd;
    
char  buff[ 101 ];
    socklen_t len 
=   sizeof (clientAdd);
    
int  closing  = 0 ;
    
while ( closing  ==   0    &&  (clientfd  =  accept(socketfd, ( struct  sockaddr  * ) & clientAdd,  & len))  > 0  )
    {
        
int  n;
        
while ((n  =  recv(clientfd,buff,  100 , 0  ))  >   0 )
        {
            printf(
" number of receive bytes = %d " , n);
            write(STDOUT_FILENO, buff, n);
            send(clientfd, buff, n, 
0 );
            buff[n] 
=   ' ' ;
            
if (strcmp(buff,  " quit " ==   0 )
            {
                
break ;
            }
            
else   if (strcmp(buff,  " close " ==   0 )
            {
                
// server closing
                closing  =   1 ;
                printf(
" server is closing " );
                
break ;
            }
        }

        close(clientfd);
    }

    close(socketfd);

    
return   0 ;
}


    经过cc编译后,即可运行。在这里我们写的程序是服务器程序,要想完成通信,也得写一个客户端程吧???
    呵呵,我们先把客户端的程序放下来,先测测我们服务器程序吧。在这里,我们使用 telnet充当客户端进行测试,telnet可以说是一个很好的客户端程序。呵呵:
本机IP为192.168.0.69,整个通信过程如下:

linyongting@linyongting: ~ $ telnet  192.168 . 0.69   8080
Trying 
192.168 . 0.69 ...
Connected to 
192.168 . 0.69 .
Escape character 
is   ' ^] ' .
hello
!  This  is  my first packet.Can you reply to me ?
hello
!  This  is  my first packet.Can you reply to me ?
Ohh, U did it
!
Ohh, U did it
!
see U next time
!!!
see U next time
!!!
quit
quit
Connection closed by foreign host.
linyongting@linyongting:
~ $ telnet  192.168 . 0.69   8080
Trying 
192.168 . 0.69 ...
Connected to 
192.168 . 0.69 .
Escape character 
is   ' ^] ' .
close
close
Connection closed by foreign host.

上面连接了两次,第一次时,与服务器通信3次,每次发信息过去后,都收到与发出来一模一样的信息。当用户输入quit的时候,服务端就会关闲与客户通信的socket,通信结束。第二次客户只输入close,服务器响应后马上关闭服务器,同时也关闭客户端。下面是服务器的显示内容:
linyongting@linyongting: ~/ program / c$ . / echoServer
socket create successfully
bind successfully
listen successfully
//第一次通信
number of receive bytes 
=   53
hello
!  This  is  my first packet.Can you reply to me ?
number of receive bytes 
=   16
Ohh, U did it
!
number of receive bytes 
=   20
see U next time
!!!
number of receive bytes 
=   6
quit
//第二次通信
number of receive bytes 
=   7
close
server 
is  closing

当客户端输入quit时,只是客户端关闭,服务器还接着为其它客服端服务。当客户端输入 close时,服务关闭。

当前出现的问题:
    我们的服务器序程只能与一个客户端进行通信,只能当客户端发出quit命令关闭后才能与下一个客户端通信。

如何解决:等待下一篇文章和大家分析一下解决方法。
  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单Linux socket 编程实例,展示了如何实现一个简单的客户端和服务器程序服务器端代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define PORT 8888 int main() { int server_fd, client_fd, valread; struct sockaddr_in address; int opt = 1; int addrlen = sizeof(address); char buffer[1024] = {0}; const char *hello = "Hello from server"; // 创建 socket 文件描述符 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // 设置 socket 选项 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { perror("setsockopt"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); // 绑定 socket 到指定地址和端口号 if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } // 监听 socket if (listen(server_fd, 3) < 0) { perror("listen"); exit(EXIT_FAILURE); } // 接受客户端连接 if ((client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) { perror("accept"); exit(EXIT_FAILURE); } // 从客户端接收数据 valread = read(client_fd, buffer, 1024); printf("%s\n", buffer); // 向客户端发送数据 send(client_fd, hello, strlen(hello), 0); printf("Hello message sent\n"); return 0; } ``` 客户端代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #define PORT 8888 int main(int argc, char const *argv[]) { int sock = 0, valread; struct sockaddr_in serv_addr; char *hello = "Hello from client"; char buffer[1024] = {0}; // 创建 socket 文件描述符 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("\n Socket creation error \n"); return -1; } memset(&serv_addr, '0', sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); // 将 IPv4 地址从点分十进制转换为二进制格式 if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { printf("\nInvalid address/ Address not supported \n"); return -1; } // 连接到服务器 if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { printf("\nConnection Failed \n"); return -1; } // 向服务器发送数据 send(sock, hello, strlen(hello), 0); printf("Hello message sent\n"); // 从服务器接收数据 valread = read(sock, buffer, 1024); printf("%s\n", buffer); return 0; } ``` 以上代码实现了一个简单的客户端和服务器程序,客户端向服务器发送 "Hello from client" 字符串,服务器接收到后向客户端发送 "Hello from server" 字符串。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值