linux网络编程之简单的回射服务器

来源:互联网 发布:linux黑客入门书籍 编辑:程序博客网 时间:2024/06/04 18:27

linux下用socket实现一个简单的回射服务器

套接字地址结构sockaddr:

struct sockaddr

 {

  unsigned short sa_family; /*地址家族, AF_xxx */

  char sa_data[14]; /*14字节协议地址*/

 }; 

一般编程并不直接针对此数据结构操作,而是使用另外一个与sockaddr等价的数据结构sockaddr_in(在netinet_in中定义):

struct sockaddr_in 

{

short int sin_family; /*通信类型*/

unsigned short int sin_port; /*端口*/

struct in_addr sin_addr; /* Internet地址*/

unsigned char sin_zero[8]; /*sockaddr结构的长度相同*/

}; 

主要用到的几个函数

socket()//创建套接字

原型:

   原型:int socket(int domain, int type, int protocol) ;

第一个参数domain指定通信协议族(protocol family),第二个为套接字类型(分为流式套接字SOCK_STREAM,数据报套接字SOCK_DGRAM,原始套接字SOCK_RAW),第三个为协议类型

bind()//绑定套接口

原型:

   原型:int bind(int sockfd, struct sockaddr *my_addr, int addrlen); 

第一个参数sockfd套接字,第二个要绑定的地址,第三个为地址长度

listen()//监听

原型:ssize_t read(int fd, void *buf, size_t count);

  第一个参数为已捆绑未连接套接口,第二个参数为最大等待队列的长度,如果未监听到则一直处于等待状态

read()//读函数

   原型:ssize_t read(int fd,void *buf,size_t count)

第一个参数fd文件描述符,第二个为指定要读入的缓冲区(指针),第三个为要读入的字节数

           该函数的作用是把fd所指的文件传送count个字节读到buf指针所指的内存中

write()//写函数

   原型:ssize_t write(int fd, const void *buf, size_t count);

第一个参数fd文件描述符,第二个为指定要入的缓冲区(指针),第三个为要入的字节数


还有几个字节转换的函数

将主机地址转换为网络地址

htons() //Host to Network Short"

htonl() //"Host to Network Long"

将网络地址转换为主机地址

ntohs() //"Network to Host Short"

ntohl() //"Network to Host Long" 


通信流程:



下面是实现回射服务器的C语言代码:

服务器端:

/*echo server*/#include<sys/socket.h>#include<sys/types.h>#include<stdio.h>#include<stdlib.h>#include<errno.h>#include <netinet/in.h>#include <arpa/inet.h>#include<unistd.h>#define ERR_EXIT(m)\do\{\perror(m);\exit(EXIT_FAILURE);\}while(0)int main(){int sockfd;struct sockaddr_in servaddr;/*服务器端地址*/struct sockaddr_in peeraddr;/*客户端地址*/int nfd,ret;char buffer[1024];socklen_t peerlen;memset(&servaddr,0,sizeof(servaddr));/*初始化*/servaddr.sin_family = AF_INET;/*指定通信协议族为IPV4*/servaddr.sin_port = htons(5188);/*绑定端口并转换成网络字符*/servaddr.sin_addr.s_addr  = htonl(INADDR_ANY);/*自动填入本机ip地址*///servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  if((sockfd=socket(AF_INET,SOCK_STREAM,0/*IPPROTO_TCP*/))==-1)    /*创建套接字*/ERR_EXIT("open socket error\n");elseprintf("create socket %d success \n",sockfd);if(bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)/*将套接字与指定端口地址相绑定*/ERR_EXIT("bind error\n");listen(sockfd,SOMAXCONN);/*监听*/ peerlen = sizeof(peeraddr);if((nfd=accept(sockfd,(struct sockaddr*)&peeraddr,&peerlen)) < 0)/*接受来自客户端的请求*/ERR_EXIT("accept error\n");/*nfd is a connected socket byte*/while(1){memset(buffer,0,sizeof(buffer));/*清空缓冲区*/ret = read(nfd,buffer,sizeof(buffer));/*读取客户端发来的消息*/fputs(buffer,stdout);write(nfd,buffer,ret);/*将消息回射给客户端*/}close(sockfd);/*关闭套接字*/close(nfd);return 0;}


客户端:

/*echo client*/#include<sys/socket.h>#include<sys/types.h>#include<stdio.h>#include<stdlib.h>#include<errno.h>#include <netinet/in.h>#include <arpa/inet.h>#include<string.h>#include<unistd.h>#define ERR_EXIT(m)\do\{\perror(m);\exit(EXIT_FAILURE);\}while(0)int main(){int sock;if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1)    ERR_EXIT("ERRO");struct sockaddr_in servaddr;char sendbuf[1024] = {0};/*发送冲区*/char recvbuf[1024] = {0};/*接收冲区*/memset(&servaddr,0,sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(5188);/*addr.sin_addr = htonl(INADDR_ANY);*/servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");  if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)/*将指定的端口地址连接服务器*/ERR_EXIT("connect error\n");while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL){write(sock,sendbuf,strlen(sendbuf));/*发送数据*/read(sock,recvbuf,sizeof(recvbuf));fputs(recvbuf,stdout);/*输出从缓冲区读入的服务器端回射回来的信息*/memset(sendbuf,0,sizeof(sendbuf));memset(recvbuf,0,sizeof(recvbuf));}close(sock);return 0;}


测试结果:

客户端:


服务器端:


1 0