那么今天继续接着上一次学习的linux网络编程:
https://wenku.baidu.com/view/32cdfa48cc22bcd126ff0ceb.html 中的最后一题
其实网络编程都是有套路的那么几个步骤,好好理解!强力推荐,以下这篇参考博客:
http://blog.csdn.net/randyjiawenjie/article/details/6895979
首先这是CS模式,可以先看到我们的源代码:
client.c(客户端代码):
运行:./server 2020
那么就可以开启服务器进程,利用端口2020进行通信,
客户端上,gcc client.c -o client
运行: ./client 服务器ip地址 2020
正常连接之后彼此就可以进行通信了。
https://wenku.baidu.com/view/32cdfa48cc22bcd126ff0ceb.html 中的最后一题
其实网络编程都是有套路的那么几个步骤,好好理解!强力推荐,以下这篇参考博客:
http://blog.csdn.net/randyjiawenjie/article/details/6895979
首先这是CS模式,可以先看到我们的源代码:
client.c(客户端代码):
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<stdlib.h>
//客户端,网络编程几步走
int main(int arg,char *args[])
{
if(arg < 3)
return -1;
int port = atoi(args[2]); //手动输入的第2个命令参数
/* 1.调用socket函数获得一个文件描述符,函数原型:int socket(int family,int type,int protocol); */
int st = socket(AF_INET,SOCK_STREAM,0);//初始化socket,协议簇是iIPv4,套接口类型是字节流套接口,返回:非负描述字---成功
struct sockaddr_in addr;//定义一个ip地址结构
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;//设置结构地址类型为tcp/ip地址
addr.sin_port = htons(port);//指定一个端口号:8080,htons:将short类型从host字节类型到net字节类型转化
addr.sin_addr.s_addr = inet_addr(args[1]);//将字符串类型的IP地址转化为int,赋给addr结构成员
/* 2.用socket建立了套接口后,调用connect为这个套接字指明远程端的地址 */
//连接到结构addr指定的ip地址和端口号
if(connect(st,(struct sockaddr *) & addr,sizeof(addr) )== -1){
// 第一个参数是socket函数返回的套接口描述字;第二和第三个参数分别是一个指向套接口地址结构的指针和该结构的大小。
printf("connect failed %s\n",strerror(errno));
return EXIT_FAILURE;
}
char s[1024];
while(1){
memset(s,0,sizeof(s));
read(STDIN_FILENO,s,sizeof(s));//从键盘读取用户输入
if(send(st,s,strlen(s),0)==-1)//发送buff的数据失败
{
printf("send failed %s\n",strerror(errno));
return EXIT_FAILURE;
}
memset(s,0,sizeof(s));
if(recv(st,s,sizeof(s),0) > 0) //如果接收数据失败,循环break
printf("recv %s\b",s);
else
break;
}
close(st);//关闭socket
return EXIT_SUCCESS;
}
server.c(服务端代码):
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
//服务端,网络编程几步走:
int main(int arg,char *args[])
{
if(arg < 2){
return -1;
}
int port = atoi(args[1]);
//1.调用socket函数获得一个文件描述符,函数原型:int socket(int family,int type,int protocol);
int st = socket(AF_INET,SOCK_STREAM,0);//初始化socket,协议簇是iIPv4,套接口类型是字节流套接口,
int on = 1;
if(setsockopt(st,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) == -1){
printf("setsockopt failed %s\n",strerror(errno));
return EXIT_FAILURE;
}
struct sockaddr_in addr;//定义一个ip地址结构
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;//将addr结构的属性定位为tcp/ip地址
addr.sin_port = htons(port);//将本地字节顺序转化为网络字节顺序
addr.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY代表这个server上所有的地址
/* 3.bind函数:为套接口分配一个本地IP和协议端口 */
//将ip与server程序绑定
if(bind(st,(struct sockaddr *) &addr,sizeof(addr)) == -1){
printf("bind failed %s\n",strerror(errno));
return EXIT_FAILURE;
}
/* 4、listen函数:listen函数仅被TCP服务器调用,
它的作用是将用sock创建的主动套接口转换成被动套接口,并等待来自客户端的连接请求 */
if(listen(st,20) == -1){
printf("listen failed %s\n",strerror(errno));
return EXIT_FAILURE;
}
char s[1024];
int client_st = 0;//client端socket
//socklen_t len = 0
struct sockaddr_in client_addr;//表示client端的ip地址
//void *p = &client_addr;
int i;
for(i = 0 ; i < 5; i++){
memset(&client_addr,0,sizeof(client_addr));
socklen_t len = sizeof(client_addr);
/* 5. accept函数:accept函数由TCP服务器调用,从已完成连接队列头返回一个已完成连接,
如果完成连接队列为空,则进程进入睡眠状态。 */
//accept会阻塞,直到有客户端连接过来,accept返回client的socket描述符
client_st = accept(st,(struct sockaddr *)&client_addr,&len);
if(client_st == -1){
printf("accept failed %s\n",strerror(errno));
return EXIT_FAILURE;
}
/* 6. inet_pton函数:将点分十进制串转换成网络字节序二进制值,
此函数对IPv4地址和IPv6地址都能处理 */
//不过这里的版本用的是 inet_ntoa 函数,将一个十进制网络字节序转换为点分十进制IP格式的字符串。
printf("accept by %s\n",inet_ntoa(client_addr.sin_addr));
while(1){
memset(s,0,sizeof(s));
int rc = recv(client_st,s,sizeof(s),0);//recv是阻塞调用
if(rc > 0)//接收来自client的信息
{
printf("recv is %s\n",s);
memset(s,0,sizeof(s));
read(STDIN_FILENO,s,sizeof(s));
send(client_st,s,strlen(s),0);
}
else{
if(rc == 0)
printf("client socket closed\n");
else
printf("recv failed %s\n",strerror(errno));
break;
}
}
close(client_st);//关闭client端socket
}
close(st);//关闭server端listen的socket
return EXIT_SUCCESS;
}
编译:gcc server.c -o server
运行:./server 2020
那么就可以开启服务器进程,利用端口2020进行通信,
客户端上,gcc client.c -o client
运行: ./client 服务器ip地址 2020
正常连接之后彼此就可以进行通信了。