| 论坛注册| 加入收藏 | 设为首页| RSS
Google
您当前的位置:首页 > Linux频道 > Linux开发区 > 软件开发

Linux socket编程实例:echo服务器程序

时间:2007-12-06 17:57:34  来源:Linux联盟收集整理  作者:
 

本文编的是echo服务器示例程序,当收到客户端的数据,服务器把数据不经加工地发送给客户。采用TCP连接,采用端口8080进行设计,在整个过程中主要涉及socket的通信。 79FLinux联盟

首先建立一个 socket,代码如下: 79FLinux联盟

int socketfd; 79FLinux联盟

socketfd = socket(AF_INET, SOCK_STREAM, 0); 79FLinux联盟

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

#include 79FLinux联盟

int socket ( int AddressFamily, int Type, int Protocol) 79FLinux联盟

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

AF_UNIX 79FLinux联盟

表示操作系统文件路径 79FLinux联盟

AF_INET 79FLinux联盟

表示Internet网络地址 79FLinux联盟

AF_NS 79FLinux联盟

表示XEROX网络地址 79FLinux联盟

Type参数表明了通信的语义,即通信连接的方式。参数为如下之一: 79FLinux联盟

SOCK_STREAM 79FLinux联盟

提供稳定可靠的连接,并且是双向的通信方式,如TCP。 79FLinux联盟

SOCK_DGRAM 79FLinux联盟

提供无连接的数据报通信,如UDP。 79FLinux联盟

SOCK_RAW 79FLinux联盟

提供该问内部网络协议和网络接口, 只有root用户才可以使用些协议。 79FLinux联盟

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

再次,把socket绑定到本机上,代码如下: 79FLinux联盟

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,然后填机服务所要开通的端口号和地址。 79FLinux联盟

sa.sin_family = AF_INET; 79FLinux联盟

>表明地址类型 79FLinux联盟

sa.sin_port = htons(EHCO_PORT); 79FLinux联盟

>端口号为8080 79FLinux联盟

sa.sin_addr.s_addr = htons(INADDR_ANY); 79FLinux联盟

>表明绑定在本机 79FLinux联盟

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

绑定完成后,服务器要侦听客户端的连接,因此首先要完成侦听设置这一过程,由listen函数实现,代码如下: 79FLinux联盟

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。 79FLinux联盟

完成侦听后,可以让客户与服务器进行连接了。服务想获得客户的请求,则需要通过 accept函数来获得。同时,需要采用一个sockaddr_in结构体来获得客户的信息。代码如下: 79FLinux联盟

int clientfd; 

struct sockaddr_in clientAdd;

char buff[101];

socklen_t len = sizeof(clientAdd);

int closing =0;

while( closing == 0 && (clientfd = accept(socketfd, 79FLinux联盟
(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函数中完成对它的填充,可依此得到客户的地址信息。 79FLinux联盟

while( closing == 0 && (clientfd = accept(socketfd, (struct sockaddr *)&clientAdd, &len)) >0 ) 79FLinux联盟

等待第一个客户,当第一个客户的请求来到服务器后,该函数会返回,clientfd为客户的socket描述符。 79FLinux联盟

接着进行通信 79FLinux联盟

while((n = recv(clientfd,buff, 100,0 )) > 0) 79FLinux联盟

等待客户的数据,收到数据后,在标准输入出显示接收的数据信息,并把它发送回给客户:send(clientfd, buff, n, 0); 79FLinux联盟

在这里,我们采用简单的命令对通信进行控制,quit表示客户要结束通信过程,而 close表示客户请求关闭服务器。关闭只需使用 close函数即可完成。 79FLinux联盟

下面是完整的代码: 79FLinux联盟

#include 

#include 

#include 

#include 

#include 

#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,79FLinux联盟
(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编译后,即可运行。在这里我们写的程序是服务器程序,要想完成通信,也得写一个客户端程吧??? 79FLinux联盟

呵呵,我们先把客户端的程序放下来,先测测我们服务器程序吧。在这里,我们使用 telnet充当客户端进行测试,telnet可以说是一个很好的客户端程序。呵呵: 79FLinux联盟

本机IP为192.168.0.69,整个通信过程如下: 79FLinux联盟

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,服务器响应后马上关闭服务器,同时也关闭客户端。下面是服务器的显示内容: 79FLinux联盟

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时,服务关闭。 79FLinux联盟

当前出现的问题: 79FLinux联盟

我们的服务器序程只能与一个客户端进行通信,只能当客户端发出quit命令关闭后才能与下一个客户端通信。 79FLinux联盟

来顶一下
近回首页
返回首页
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
相关文章
栏目更新
栏目热门