Linux下TCP通信简单实例
作者:网络转载 发布时间:[ 2014/2/19 9:50:56 ] 推荐标签:TCP通信 操作系统 Linux
基于TCP(面向连接)的socket编程,分为服务器端和客户端
服务器端的流程如下:
(1)创建套接字(socket)
(2)将套接字绑定到一个本地地址和端口上(bind)
(3)将套接字设为监听模式,准备接收客户端请求(listen)
(4)等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)
(5)用返回的套接字和客户端进行通信(send/recv)
(6)返回,等待另一个客户请求。
(7)关闭套接字。
客户端的流程如下:
(1)创建套接字(socket)
(2)向服务器发出连接请求(connect)
(3)和服务器端进行通信(send/recv)
(4)关闭套接字
下面通过一个具体例子讲解一下具体的过程和相关的函数,环境是suse linux。
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <memory.h>
#include <unistd.h>
//#include <linux/in.h>
#include <netinet/in.h>
//#include <linux/inet_diag.h>
#include <arpa/inet.h>
#include <signal.h>
/**
关于 sockaddr sockaddr_in socketaddr_un说明
http://maomaozaoyue.blog.sohu.com/197538359.html
*/
#define PORT 11910 //定义通信端口
#define BACKLOG 5 //定义侦听队列长度
#define buflen 1024
void process_conn_server(int s);
void sig_pipe(int signo);
int ss,sc; //ss为服务器socket描述符,sc为某一客户端通信socket描述符
int main(int argc,char *argv[])
{
struct sockaddr_in server_addr; //存储服务器端socket地址结构
struct sockaddr_in client_addr; //存储客户端 socket地址结构
int err; //返回值
pid_t pid; //分叉进行的ID
/*****************socket()***************/
ss = socket(AF_INET,SOCK_STREAM,0); //建立一个序列化的,可靠的,双向连接的的字节流
if(ss<0)
{
printf("server : server socket create error
");
return -1;
}
//注册信号
sighandler_t ret;
ret = signal(SIGTSTP,sig_pipe);
if(SIG_ERR == ret)
{
printf("信号挂接失败
");
return -1;
}
else
printf("信号挂接成功
");
/******************bind()****************/
//初始化地址结构
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET; //协议族
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //本地地址
server_addr.sin_port = htons(PORT);
err = bind(ss,(struct sockaddr *)&server_addr,sizeof(sockaddr));
if(err<0)
{
printf("server : bind error
");
return -1;
}
/*****************listen()***************/
err = listen(ss,BACKLOG); //设置监听的队列大小
if(err < 0)
{
printf("server : listen error
");
return -1;
}
/****************accept()***************/
/**
为类方便处理,我们使用两个进程分别管理两个处理:
1,服务器监听新的连接请求;2,以建立连接的C/S实现通信
这两个任务分别放在两个进程中处理,为了防止失误操作
在一个进程中关闭 侦听套接字描述符 另一进程中关闭
客户端连接套接字描述符。注只有当所有套接字全都关闭时
当前连接才能关闭,fork调用的时候父进程与子进程有相同的
套接字,总共两套,两套都关闭掉才能关闭这个套接字
*/
for(;;)
{
socklen_t addrlen = sizeof(client_addr);
//accept返回客户端套接字描述符
sc = accept(ss,(struct sockaddr *)&client_addr,&addrlen); //注,此处为了获取返回值使用 指针做参数
if(sc < 0) //出错
{
continue; //结束此次循环
}
else
{
printf("server : connected
");
}
//创建一个子线程,用于与客户端通信
pid = fork();
//fork 调用说明:子进程返回 0 ;父进程返回子进程 ID
if(pid == 0) //子进程,与客户端通信
{
close(ss);
process_conn_server(sc);
}
else
{
close(sc);
}
}
}
/**
服务器对客户端连接处理过程;先读取从客户端发送来的数据,
然后将接收到的数据的字节的个数发送到客户端
*/
//通过套接字 s 与客户端进行通信
void process_conn_server(int s)
{
ssize_t size = 0;
char buffer[buflen]; //定义数据缓冲区
for(;;)
{
//等待读
for(size = 0;size == 0 ;size = read(s,buffer,buflen));
//输出从客户端接收到的数据
printf("%s",buffer);
//结束处理
if(strcmp(buffer,"quit") == 0)
{
close(s); //成功返回0,失败返回-1
return ;
}
sprintf(buffer,"%d bytes altogether
",size);
write(s,buffer,strlen(buffer)+1);
}
}
void sig_pipe(int signo)
{
printf("catch a signal
");
if(signo == SIGTSTP)
{
printf("接收到 SIGTSTP 信号
");
int ret1 = close(ss);
int ret2 = close(sc);
int ret = ret1>ret2?ret1:ret2;
if(ret == 0)
printf("成功 : 关闭套接字
");
else if(ret ==-1 )
printf("失败 : 未关闭套接字
");
exit(1);
}
}
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11