linux socke编程实例:一个简单的echo服务器程序
Posted 海枫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux socke编程实例:一个简单的echo服务器程序相关的知识,希望对你有一定的参考价值。
也许是第一次真正使用linux操作系统,忽然对丢弃已久的C产生了很大的兴趣,最近想学点linux的知识,在linux的世界里面,接触得最多的还是C,故有感写一下linux的socket程序。
也许很多朋友会像我一样,这样的程序在Java写得太多,以至对Socket的通信细节还不曾忘怀。由于未有linux下 的 编程经验,在写程序过程中碰到很多不懂的东西,经过google一翻后,终于把一些基本的东西搞懂了。好了,闲话少讲,下面说说编程的想法。
本文编的是echo服务器示例程序,当收到客户端的数据,服务器把数据不经加工地发送给客户。采用TCP连接,采用端口8080进行设计,在整个过程中主要涉及socket的通信。
首先建立一个 socket,代码如下:
socket函数是我们写socket程序遇到的第一个函数,它在指定的协议上创建一个socket,它的函数说明如下所示:
#include <sys/socket.h>
int socket ( int AddressFamily, int Type, int Protocol)
其中:AddressFamily参数指定socket操作中所要解释的网络地址类型,值为如下之一:
返回值:成功则返socket描述符,出错则返回-1,可通过errno代码进行查看错误原因。
再次,把socket绑定到本机上,代码如下:
上面的代码中,定义一个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函数实现,代码如下:
listen(socketfd, MAX_CLIENT_NUM)表明在socketfd上侦听,其中客户个数最大值为MAX_CLIENT_NUM。
完成侦听后,可以让客户与服务器进行连接了。服务想获得客户的请求,则需要通过 accept函数来获得。同时,需要采用一个sockaddr_in结构体来获得客户的信息。代码如下:
其中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函数即可完成。
下面是完整的代码:
经过cc编译后,即可运行。在这里我们写的程序是服务器程序,要想完成通信,也得写一个客户端程吧???
呵呵,我们先把客户端的程序放下来,先测测我们服务器程序吧。在这里,我们使用 telnet充当客户端进行测试,telnet可以说是一个很好的客户端程序。呵呵:
本机IP为192.168.0.69,整个通信过程如下:
上面连接了两次,第一次时,与服务器通信3次,每次发信息过去后,都收到与发出来一模一样的信息。当用户输入quit的时候,服务端就会关闲与客户通信的socket,通信结束。第二次客户只输入close,服务器响应后马上关闭服务器,同时也关闭客户端。下面是服务器的显示内容:
当客户端输入quit时,只是客户端关闭,服务器还接着为其它客服端服务。当客户端输入 close时,服务关闭。
当前出现的问题:
我们的服务器序程只能与一个客户端进行通信,只能当客户端发出quit命令关闭后才能与下一个客户端通信。
如何解决:等待下一篇文章和大家分析一下解决方法。
也许很多朋友会像我一样,这样的程序在Java写得太多,以至对Socket的通信细节还不曾忘怀。由于未有linux下 的 编程经验,在写程序过程中碰到很多不懂的东西,经过google一翻后,终于把一些基本的东西搞懂了。好了,闲话少讲,下面说说编程的想法。
本文编的是echo服务器示例程序,当收到客户端的数据,服务器把数据不经加工地发送给客户。采用TCP连接,采用端口8080进行设计,在整个过程中主要涉及socket的通信。
首先建立一个 socket,代码如下:
int socketfd;
socketfd = socket(AF_INET, SOCK_STREAM, 0);
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网络地址
-
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 " );
}
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 ");
}
{
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);
}
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 ;
}
#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.
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
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命令关闭后才能与下一个客户端通信。
如何解决:等待下一篇文章和大家分析一下解决方法。
以上是关于linux socke编程实例:一个简单的echo服务器程序的主要内容,如果未能解决你的问题,请参考以下文章