Linux下的TCP/IP编程----实践篇

时间:2021-05-21 10:21:08

在了解了socket编程的基础知识之后就可以开始尝试编写一个简单的TCP/IP的服务端/客户端程序了。

首先来梳理一下卡客户端和服务端的操作流程:

服务端:

创建socket——绑定地址(IP地址+端口地址)——监听连接请求——接受连接请求——进行数据交换

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
//函数声明
void error_handling(char *message);

int main(int argc,char *argv[ ] ){

//客户端和服务端的socket描述符
int serv_sock;
int clent_sock;
//客户端和服务端的地址
struct sockaddr_in serv_addr;
struct sockaddr_in clent_addr;

//客户端地址大小
socklen_t client_addr_size;

//要发送的消息
char messages [] = {"Hello World"};

if(argc!=2){
printf("Usage : %s <port> \n",argv[0]);
exit(1);
}

//设置服务端socket使用的协议和连接方式
serv_sock = socket(PF_INET,SOCK_STREAM,0);
//进行检查
if(serv_sock == -1){
error_handling("socket() error");
}
//初始化server_addr所申请的内存空间
memset(&serv_addr,0,sizeof(serv_addr));

//为serve_addr结构体设置使用协议,IP地址,端口号
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(atoi(argv[1]));
//进行地址绑定
if(bind(serv_sock,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) == -1){
error_handling("bind() error");
}

//设置监听
if(listen(serv_sock,5) == -1){
error_handling("listen() error");
}
//获取客户端的地址大小
client_addr_size = sizeof(clent_addr);

//监听到后接收请求,并使用服务端本地的客户端代理,以便于服务端能继续接受新的连接请求
clent_sock = accept(serv_sock,(struct sockaddr *) &clent_addr,&client_addr_size);

if(clent_sock == -1){
error_handling("accept() error");
}

//向客户端传送数据
write(clent_sock,messages,sizeof(messages));
close(clent_sock);
close(serv_sock);

return 0;
}

//出错处理
void error_handling(char * message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}

客户端:

创建socket——输入服务端地址和端口号进行连接请求——进行数据的交换

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>

void error_handling(char *message);

int main(int argc,char* argv[]){
//本地socket描述符
int socket;
//服务端socket地址
struct sockaddr_in server_addr;
//存储接收到的字符串
char message[30];
//接收到的字符串长度
int str_len;

//检查参数的个数是否合法
if(argc != 3){
printf("Usage : % <IP> <PORT> \n",argv[0]);
exit(1);
}

//创建客户端的socket,并指定使用协议,连接方式。
socket = socket(PF_INET,SOCK_STREAM,0);
//初始化server_addr所申请的内存空间
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
server_addr.sin_port = htons(atoi(argv[2]));

//进行连接请求
if(connect(socket,(struct sockaddr *) &server_addr,sizeof(server_addr)) == -1){
error_handling("connect() error");
}

//连接成功则读取数据
str_len = read(socket,message,sizeof(message));
if(str_len == -1){
error_handling("read() error");
}

//打印接收到的信息
printf("message from Server : %s \n ",message);
close(socket);

return 0;
}

void error_handling(char * message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}

编译运行:

编译服务端程序:

weiqingcai@weiqingcai-Inspiron-7447:~/桌面 $ cd studyProjects/
weiqingcai@weiqingcai-Inspiron-7447:~/桌面/studyProjects $ gcc -o server server.c

编译客户端程序:

weiqingcai@weiqingcai-Inspiron-7447:~/桌面 $ cd studyProjects/
weiqingcai@weiqingcai-Inspiron-7447:~/桌面/studyProjects $ gcc -o client client.c

首先运行服务端:

weiqingcai@weiqingcai-Inspiron-7447:~/桌面/studyProjects $ ./server 9999

之后命令行光标会一直不动,等待连接请求。

然后运行客户端:

weiqingcai@weiqingcai-Inspiron-7447:~/桌面/studyProjects $ ./client 127.0.0.1 9999
message from Server : Hello World

消息会直接从服务端返回,同时服务端也结束运行

至此一个简单的服务端/客户端的程序就写好了。

梳理一遍整个流程:

首先服务端要先运行起来,保证客户端请求时能够给出响应。服务端程序要先创建自己的套接字,然后为套接字绑定地址(IP地址和端口号),然后使其进入监听状态,在有客户端请求时需要接受客户端请求,进行通讯。

对于客户端而言,首先建立自己的socket,然后就是请求连接服务端,在连接成功之后就可以进行数据的读写。

然后我们可以对这个简单的服务端/客户端程序进行不断的完善