在了解了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,然后就是请求连接服务端,在连接成功之后就可以进行数据的读写。
然后我们可以对这个简单的服务端/客户端程序进行不断的完善