Linux服务器、客户端通信套接字代码超详解

代码在下面已经进行了详细注释!(往后翻)

具体效果怎么看呢?
1.首先打开Linux虚拟机
2.用命令mkdir建立一个socket目录
3.在目录里面用 vi server.c 建立一个.c文件
4.把服务器的代码输进去(按i输入)
5. :wq保存退出
6. gcc server.c -o sever -Wall -g 对这个文件进行编译
-Wall 是输出警告信息
-g代表可执行程序包含调试信息

这样生成的可执行程序 sever,./sever 运行它就是在运行一个服务器。

7.利用alt+ctrl+t再打开一个命令框
8.输入:nc 127.0.0.1 9527(程序中的端口号)(前两个字母代表网络连接)
这样就和你写的服务器建立了连接
9.这时输入一个小写hello,就会返回一个大写的HELLO。另一个命令框会返回客户端IP和端口号!
10.实验成功!

在客户端那里:
1.在目录里面用 vi server.c 建立一个client.c文件
2.把客户端的代码输进去(按i输入)
3. :wq保存退出
4. gcc client.c -o client -Wall -g 对这个文件进行编译

最后:
利用两个窗口,一个./server运行服务器程序
一个./client运行客户端程序

最后就会在两端同时出现大写小写的hello出现9次。
实验成功!

在这里插入图片描述

服务器程序:

#include<stdio.h>//输入输出
#include<stdlib.h>//动态内存分配
#include<string.h>

//linux下有这个头文件,vc下没有
//它包含很多UNIX系统服务的函数原型,eg:read write函数等
#include<unistd.h>

#include<errno.h>
#include<pthread.h>//包含有关多线程的函数

#include <sys/socket.h>//套接字函数、bind函数头文件
#include<ctype.h>//转小写转大写函数的头文件,在第二个地址结构的时候用
#include<arpa/inet.h>//bind的头文件

#define SERV_PORT 9527 //bind函数中的端口号

char buf[BUFSIZ], clint_IP[1024];//用来保存读到的客户端的数组,BUFSIZ默认4096
//上面第二个数组用来接收客户端IP地址

void sys_err(const char *str)
{
	//perror是用来输出错误的,如果某些函数调用不正确的话,调用perror会先输出错误号,然后输出你在perror()参数中指定的内容
	perror(str);//包含在stdlib.h这个头文件中
	exit(1);
}

int main(int argc, char *argv[])
{
	int ifd =0,cfd=0,ret;//保存文件描述符,用于后期和服务器建立连接
	socklen_t clit_addr_len;

	//定义bind函数中用到的ip地址结构体
	struct sockaddr_in serv_addr, clit_addr;
	serv_addr.sin_family = AF_INET;//协议簇地址,和第三个参数的区别在于,这个是地址类型,第三个是有效实际地址
	//TCP/IP是一个网络通讯协bai议群,它包含了很多通信协议。这些协du议制定了网zhi络设备、计算机连入网络以及数据是如何dao在它们之间进行传输的标准。
	//TCP协议又叫传输控制协议,作用于传输层。IP协议又叫网络间互联协议,工作在网络层。它们都是TCP/IP协议簇中非常重要的协议。
	serv_addr.sin_port = htons(SERV_PORT);//端口这里需要字节序的转换!需要来回传的都需要转换!
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//取出系统中任意有效的IP地址

	//sin_family和sin_addr.s_addr的地址有什么区别?

	//socket目的:创建一个套接字
	//第一个参数是协议簇,代表网络层协议
	//第二个参数是个协议,数据传输协议,代表传输层协议
	//第三个参数是:你所选用的数据传输协议的代表协议,比如流式数据传输协议(SOCK_STREAM)的代表协议是tcp
	//成功:返回指向新创建的socket的文件描述符,失败:返回-1,
	ifd = socket(AF_INET, SOCK_STREAM, 0);
	if(ifd==-1)
	{
		sys_err("socket error");
	}

	//bind作用:将socket和bind的第二个参数中的地址、端口号捆绑起来,以便监听
	//第一个参数服务器端套接字描述符、  第二个参数是个结构体指针,里面包含服务器的IP地址+端口号、第三个参数是这个地址的长度
	bind(ifd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));//和上面返回描述符不同,这个返回的是0

	listen(ifd, 128);//第二个参数是它所能监听的最大上限数

	clit_addr_len=sizeof(clit_addr);

	//第二个参数是接收链接客户端地址信息,含IP地址和端口号,所以前面不需要专门定义
	//返回一个套接字
	cfd=accept(ifd, (struct sockaddr*)&clit_addr ,&clit_addr_len);//注意第三个参数类型,相比第bind多一个指针
	if(cfd == -1)
	{
		sys_err("accept error");
	}
	//把接收到的客户端IP和端口号打印出来,都在上面的clit_addr里面
	//inet_ntop目的是将二进制转换为10进制输出,第二个参数是客户的IP地址,第三个参数是用来接收的数组,第四个是长度
	printf("clint IP:%s port:%d\n",inet_ntop(AF_INET,&clit_addr.sin_addr.s_addr,clint_IP,sizeof(clint_IP)),
		ntohs(clit_addr.sin_port));

	while(1)
	{
		ret=read(cfd,buf,sizeof(buf));//返回字节数
		write(STDOUT_FILENO,buf,ret);标准输出到屏幕
		for(int i=0; i<ret;i++)
		{
			buf[i]=toupper(buf[i]);
		}
		write(cfd,buf,ret);//把buf的内容写回到客户端
	}
	close(ifd);
	close(cfd);
	return 0;
}

客户端编程:

#include<stdio.h>
#include<stdlib.h>//动态内存分配
#include<string.h>
//linux下有这个头文件,vc下没有
//它包含很多UNIX系统服务的函数原型,eg:read write函数等
#include<unistd.h>

#include<errno.h>
#include<pthread.h>//包含有关多线程的函数

#include <sys/types.h> 	//connect函数中第二个参数用
#include <sys/socket.h>//套接字的函数
#include<arpa/inet.h>//bind的头文件、inet_pton函数头文件

#define SERV_PORT 9527 //bind函数中的端口号
char buf[BUFSIZ];
void sys_err(const char *str)
{
	//perror是用来输出错误的,如果某些函数调用不正确的话,调用perror会先输出错误号,然后输出你在perror()参数中指定的内容
	perror(str);//包含在stdlib.h这个头文件中
	exit(1);
}

int main(int argc, char *argv[])
{
	struct sockaddr_in serv_addr;
	serv_addr.sin_family = AF_INET;//协议簇地址,和第三个参数的区别在于,这个是地址类型,第三个是有效实际地址
	serv_addr.sin_port = htons(SERV_PORT);//一定要和服务器的相同
	//第二个参数是服务器的IP地址,要把这个参数传到第三个里面,然后就不用写下面这句了
	//客户端绑定服务器的时候用inet_pton这个函数,服务器绑定的时候一定要用二进制的绑
	inet_pton(AF_INET,"127.0.0.1",&serv_addr.sin_addr.s_addr);
	//serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//取出系统中任意有效的IP地址

	//创建套接字
	int cfd=socket(AF_INET, SOCK_STREAM, 0);
	if(cfd==-1)
	{
		sys_err("socket error");
	}

	//第二个参数:传入参数,指定服务器端地址信息,含IP地址和端口号
	//成功返回0.失败返回-1
	int ret= connect(cfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
	if(ret==-1)
	sys_err("connect error"); 
	int conter=10;
	while(conter--)
	{
		//第二个参数是写给服务器的,第三个是hello的长度
		write(cfd,"hello\n",6);
		
		//服务器会返回信息,把小写hello变为大写返回
		ret = read(cfd,buf,sizeof(buf));
		write(STDOUT_FILENO,buf,ret);//标准输出到屏幕
		sleep(1);
	
	close(cfd);

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值