下图是基于TCP协议的客户端/服务器程序的一般流程:
/*server.c time 命令时间*/
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h> //很重要的库,inet_ntop函数源于此。
#include <stdlib.h>
#include <time.h>
#include <string.h> //not strings.h
#define SERVER_PORT 20000 //define the defualt connect port id
#define BUFFER_SIZE 255
#define LENGTH_OF_LISTEN_QUEUE 20
int main(void)
{
pid_t childpid; //定义新fork()进程的pid
int servfd, clifd; //服务器套接字,和客户端套接字
struct sockaddr_in servaddr,cliaddr;
socklen_t chiaddr_len;
char buf[BUFFER_SIZE], strtmp[BUFFER_SIZE];
time_t timestamp;
//socket()打开一个网络通讯端口
servfd = socket(AF_INET, SOCK_STREAM, 0 );
/*首先将整个结构体清零,然后设置地址类型为AF_INET,网络地址为INADDR_ANY,这个宏表示本地的任意IP地址,因为服务器可能有多个网 卡,每个网卡也可能绑定多个IP地址,这样设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP地址,端口号为 SERV_PORT,我们自己定义为8000。*/
bzero( &servaddr, sizeof( servaddr ) );
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERVER_PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(servfd, (struct sockaddr*) &servaddr, sizeof(servaddr)); //用bind绑定一个固定的网络地址和端口
/*listen()声明sockfd处于监听状态,并且最多允许有backlog个客户端处于连接待状态,如果接收到更 多的连接请求就忽略。*/
listen(servfd, LENGTH_OF_LISTEN_QUEUE);
printf("accepting conections ...\n");
while(1)
{ //server loop will nerver exit unless any body kill the process
chiaddr_len = sizeof(cliaddr);
/*服务器调用accept()接受连接,如果服务器调用accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来。cliaddr是 一个传出参数,accept()返回时传出客户端的地址和端口号。addrlen参数是一个传入传出参数(value-result argument),传入的是调用者提供的缓冲区cliaddr的长度以避免缓冲区溢出问题,传出的是客户端地址结构体的实际长度(有可能没有占满调用者 提供的缓冲区)。如果给cliaddr参数传NULL,表示不关心客户端的地址*/
clifd = accept(servfd,( struct sockaddr * ) &cliaddr, &chiaddr_len);
if( childpid = fork(),childpid == 0 ) //注意fork() create a child processOn success, the PID of the child process is returned in //the parent’s thread of execution, and a 0 is returned in the child’s thread of execution.
{
close(servfd); //关掉子进程的sevfd
printf( " from client,IP:%s,Port:%d\n ",inet_ntop(AF_INET, &cliaddr.sin_addr, buf,sizeof(buf)),ntohs(cliaddr.sin_port));
while(1)
{
read(clifd,buf,BUFFER_SIZE);
//对传来的命令进行处理
if( strncmp(buf, "time",4) == 0)
{
timestamp = time(NULL);
snprintf(buf, sizeof(buf), "%.24s\r\n",ctime( ×tamp ));
write(clifd,buf,strlen(buf));
}
else
{
snprintf(strtmp, sizeof(strtmp),"%s","Sorry! commond not found!\n");
write(clifd,strtmp,strlen(strtmp));
}
}
close(clifd); //关掉子进程的clifd
exit(0);
} //if
close(clifd); //关掉父进程的clifd套接字
}
return 0;
}
/*client316.c*/
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#define MAXLINE 80
#define SERV_PORT 20000
int main(int argc, char **argv)
{
struct sockaddr_in servaddr;
char buf[MAXLINE];
int sockfd,n;
char str[MAXLINE];
sockfd = socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET,"192.168.13.128", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
connect(sockfd, (struct sockaddr *) & servaddr, sizeof(servaddr)); //connect绑定服务器套接字,地址等信息
while(fgets(str,MAXLINE,stdin) != NULL) //从屏幕中读取一行数据
{
write(sockfd,str,strlen(str));
n = read(sockfd,buf,MAXLINE);
if(n == 0)
{
printf("Server has been closed.\n");
break;
}
else
{
write(STDOUT_FILENO, "Response from server:",21);
write(STDOUT_FILENO, buf, n);
}
}
close(sockfd);
return 0;
}
/*makefile*/
all: server client
server:server315.c
gcc $^ -o $@
client:client316.c
gcc $^ -o $@
操作步骤:1.新建 vi server315.c 并写入代码。然后保存esc,:wq
2.新建 vi client316.c 并写入代码。然后保存esc,:wq
3.新建vi makefile并写入代码。然后保存esc,:wq
4.执行命令make
5.执行./server
6.clone Session(新建一个窗口)。执行命令./client
7.输入命令。如是time.则返回服务器当前时间。
注: 部分内容(如流程图)参考Linux_C一站式学习_最新版.pdf
类别:网络编程 查看评论文章来源:
http://hi.baidu.com/wgcno7/blog/item/1b54e214e3fb2814962b4344.html