一个基于TCP协议的服务器/客户端的简单例子

1、服务器端程序(tcp_server.c)

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>

extern void sig_process(int signo);
extern void sig_pipe(int signo);

#define SERV_PORT 8888 /* 监听端口地址 */
#define BACKLOG 2 /* 监听队列长度 */

int main(int argc, char *argv[]){
int listen_fd, conn_fd;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;

/* 设置信号处理函数 */
signal(SIGINT, sig_process);
signal(SIGPIPE, sig_pipe);

/* 创建一个流式套接字 */
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if(listen_fd == -1){
perror("scoket failed");
exit(1);
}

/* 设置服务器地址 */
bzero(&serv_addr, sizeof(struct sockaddr_in)); /* 清零 */
serv_addr.sin_family = AF_INET; /* 协议族 */
serv_addr.sin_port = htons(SERV_PORT); /* 服务器端口 */
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* 本地地址(自动) */

/* 绑定地址到套接字描述符 */
if(bind(listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1){
perror("bind failed");
exit(1);
}

/*设置监听队列*/
if(listen(listen_fd, BACKLOG) == -1){
perror("listen failed");
exit(1);
}
/* 主循环过程,接收并处理客户端请求 */
for(; ; ){
/* 接受客户端请求 */
int addrlen = sizeof(struct sockaddr);
/* 生成一个新的套接字文件描述符来处理连接请求 */
conn_fd = accept(listen_fd, (struct sockaddr *)&cli_addr, &addrlen);
if(conn_fd == -1){
perror("accept failed");
continue; /* 出错,结束本次循环,继续运行 */
}
/* 处理到来的连接 */
if(fork() == 0){ /* 新建子进程,避免僵尸进程,将先于其子进程结束 */
if(fork() == 0){ /* 新建子进程的子进程来处理连接请求 */
close(listen_fd); /* 关闭服务器的监听 */
process_conn_server(conn_fd); /* 处理连接 */
}
else{
exit(0); /* 子进程先退出 */
}
}
else{
close(conn_fd); /* 在父进程中关闭客户端连接 */
}
}
}

2、客户端程序(tcp_client.c)

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>

extern void sig_process(int signo);
extern void sig_pipe(int signo);

#define SERV_PORT 8888

int main(int argc, char *argv[]){
int sock_fd;
struct sockaddr_in server_addr;

/* 设置信号处理函数 */
signal(SIGINT, sig_process);
signal(SIGPIPE, sig_pipe);

/* 创建一个流式套接字 */
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if(sock_fd == -1){
perror("socket failed");
exit(1);
}

/* 设置服务器地址 */
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERV_PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

/*将用户输入的字符串类型的IP地址转换为二进制形式*/
inet_pton(AF_INET,argv[1],&server_addr.sin_addr);

/* 连接服务器 */
connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
/* 客户端处理过程 */
process_conn_client(sock_fd);
/* 关闭连接 */
close(sock_fd);
}

3、信息处理(tcp_process.c):使用read()和write()函数

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* 服务器对客户端的处理 */
void process_conn_server(int client_fd){
char buffer[1024]; /* 数据缓冲区 */
ssize_t size = 0;

for(; ; ){
size = read(client_fd, buffer, 1024); /* 从套接字中读取数据到缓冲区 */
if(size <= 0){
perror("read failed");
return;
}
sprintf(buffer, "%d bytes altogether\n", size); /* 将数据写入缓冲区 */
write(client_fd, buffer, strlen(buffer)+1); /* 将缓冲区中的数据写入套接字 */
}
}

/* 客户端的处理过程 */
void process_conn_client(int server_fd){
char buffer[1024];
ssize_t size = 0;

for(; ; ){
/* 从标准输入中读取数据放到缓冲区buffer中 */
size = read(0, buffer, 1024);
if(size <= 0){
perror("read failed");
return;
}
write(server_fd, buffer, size); /* 将缓冲区中的数据写入套接字 */
size = read(server_fd, buffer, 1024); /* 从套接字中读取数据到缓存区 */
write(1, buffer, size); /* 将缓冲区中的数据输出到标准输出上 */
}
}

/* 信号SIGINT的处理函数 */
void sig_process(int signo){
printf("Catch a exit signal\n");
_exit(0);
}

/* 信号SIGPIPE的处理函数 */
void sig_pipe(int signo){
printf("Cathc a SIGPIPE signal\n");
/*释放资源*/
}

4、编译运行程序
(1)建立Makefile文件:

all:client server #all规则,它依赖于client和server规则

client:tcp_client.o tcp_process.o #client规则,生成客户端可执行程序
gcc tcp_client.o tcp_process.o -o client
server:tcp_server.o tcp_process.o #server规则,生成服务器端可执行程序
gcc tcp_server.o tcp_process.o -o server

clean: #清理规则,删除client、server和中间文件
rm -f client server *.o

(2)编译运行:
先编译:
[img]http://dl.iteye.com/upload/attachment/0077/5953/79cd451b-5c73-3ba6-a4b4-656f89f8c19e.png[/img]
在运行,先server,后client:
[img]http://dl.iteye.com/upload/attachment/0077/5955/19032b91-8230-33cf-b42e-760efdf02442.png[/img]
使用netstat命令查看网络连接状态:
[img]http://dl.iteye.com/upload/attachment/0077/5957/73dd5b10-9c0e-3f69-8682-3949b4ecfdff.png[/img]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值