网络编程:TCP 客户端/服务端简单例子
写在前面的话
该例子比较简单,注释得也比较仔细。适合小白学习网络编程。了解TCP下C/S模型编程的基本流程,后续学习,复杂功能其实在process_xx函数实现即可。参考教材:Linux网络编程(第二版)
前置知识:1.多进程:fork()函数 2.linux:标准输入0,标准输出1,标准错误2 3.socket:几个常用API
题目(功能描述)
客户端:1.客户端连接连接服务端后,从标准输入字符串发送给客户端。2.接收到客户端消息后打印出接收到的消息
服务端:服务端接收客户端发送的消息,并计算出接收到的字符总数,发回给客户端
服务端代码
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 54321
#define BACKLOG 2
//服务端对客户端的处理
void process_coon_server(int s)
{
ssize_t size = 0;
char buffer[1024]; //数据缓冲区
while (1)
{
//从套接字读取数据放到缓冲区
size = read(s, buffer, 1024);
//没有数据可读
if (size == 0)
{
return;
}
//构建收到的字符串
sprintf(buffer, "%d bytes altogether\n", size);
//发送给客户端
write(s, buffer, strlen(buffer) + 1);
}
}
int main(int argc, char *argv[])
{
int pid;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
//建立流式套接字
int ss = socket(AF_INET, SOCK_STREAM, 0);
if (ss < 0)
{
printf("make socket error.\n");
return -1;
}
//设置服务器地址
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT);
//绑定
int errb = bind(ss, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (errb < 0)
{
printf("bind error.\n");
return -1;
}
//监听
int errl = listen(ss, BACKLOG);
if (errl < 0)
{
printf("listen error .\n");
return -1;
}
while (1)
{
socklen_t addrlen = sizeof(struct sockaddr);
//接收客户端连接
int sc = accept(ss, (struct sockaddr *)&client_addr, &addrlen);
//出错,结束本次循环
if (sc < 0)
{
continue;
}
//建立新进程处理客户端连接
pid = fork();
if (pid == 0)
{
//为了防止误操作,在子进程将监听的socket关闭
close(ss);
//处理客户端请求
process_coon_server(sc);
}
else
{
//为了防止误操作,在父进程将连接的socket关闭
close(sc);
}
}
}
客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <assert.h>
#define PORT 54321
//服务端对客户端的处理
void process_coon_client(int s)
{
ssize_t size = 0;
char buffer[1024]; //数据缓冲区
while (1)
{
size = read(0, buffer, 1024);
if (size > 0)
{
write(s, buffer, size); //发送给服务器
size = read(s, buffer, 1024); //从服务器读取数据
write(1, buffer, size); //写到标准输出
}
}
}
int main(int argc, char *argv[])
{
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
//建立流式套接字
int ss = socket(AF_INET, SOCK_STREAM, 0);
assert(ss >= 0);
//设置服务器地址
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(PORT);
//将用户输入的字符串IP转换
inet_pton(AF_INET, argv[1], &server_addr.sin_addr);
//连接服务器
connect(ss, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
process_coon_client(ss);
//关闭连接
close(ss);
return 0;
}
效果演示
可以看到,程序实现了预期的基本功能。
查看连接情况
可以看到连接建立是成功的,52410是操作系统为客户端分配的随机端口,54321是服务端监听端口。