文章目录
前言
socket网络编程实liunx系统编程中非常重要的一部分,我们知道,在本地的进程间通信有很多种,但这些通信方式都只是建立在本地服务器的基础之上的,当我们是在两个不同的端口处时,这个时候,进程间通信的方式就没有用了,我们需要利用网络进行通信,而socket编程,则可以实现这一功能。
一、socket网络编程介绍
1.什么是socket
socket是用于bai在两个基于duTCP/IP协议的应用程序之间相互zhi通信。最早出现在daoUNIX系统zhuan中,是UNIX系统主要的信息传递方式。在shuWINDOWS系统中,SOCKET称为WINSOCK。
socket(也叫套接字)最初是在Unix系统上开发的网络通信的接口。
后来微软等公司将它移植到了windows下,当然原来unix系统下的还是好用的。
对于socket可以这样理解:
它就是一个函数库,里面包括大量的函数和相应的数据结构,已经实现好了。
它支持网络通信。
程序开发人员可以通过阅读相关的函数文档,了解函数的使用方法,进行网络的编程。
两种形式的socket:流式套接字,对应与TCP协议。
简单来讲,Socket是网络应用程序接口,是应用层到传送层的接口。也就是用户进程,与系统内核的接口,即API。
2.相关api的介绍
a socket函数:
介绍创建一个套接口()。
#include <sys/socket.h>
int socket( int af, int type, int protocol);
af:一个地址描述。仅支持AF_INET格式,也就是说ARPA Internet地址格式。
type:指定socket类型。新套接口的类型描述类型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
protocol:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。常用的协议有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
b bind函数:
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
c listen函数:
int listen(int sockfd, int backlog);
d accept函数
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
3.socket服务端的创建步骤
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();
3、绑定IP地址、端口等信息到socket上,用函数bind();
4、开启监听,用函数listen();
5、接收客户端上来的连接,用函数accept();
6、收发数据,用函数send()和recv(),或者read()和write();
4.socket客户端的创建步骤
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();
3、绑定IP地址、端口等信息到socket上,用函数bind();
4、设置要连接的对方的IP地址和端口等属性;
5、连接服务器,用函数connect();
6、收发数据,用函数send()和recv(),或者read()和write();
二、服务端与客户端的实现
1.服务端的实现
代码如下
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc,char **argv )//定义参数,使得ip地址和端口号可以手动输入
{
int socketid;
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
int len;
int c_fd;
int n_read;
char redbuf[128]={0};
//初始化两个数组,用于发送消息和接受消息
char msg[128]={0};
if(argc!=3){
printf("param is not good\n");
exit(-1);
}
len=sizeof(struct sockaddr_in);
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
socketid=socket(AF_INET,SOCK_STREAM,0);
if(socketid==-1)
{
perror("socket");
exit(-1);
}
s_addr.sin_family=AF_INET;
s_addr.sin_port=htons(atoi(argv[2]));
inet_aton(argv[1],&s_addr.sin_addr);
bind(socketid,(struct sockaddr *)&s_addr,len);
listen(socketid,10);
while(1){//利用while(1)死循环使得服务端能不断接受客户端的消息
c_fd=accept(socketid,(struct sockaddr *)&c_addr,&len);
if(c_fd==-1){
perror("accept");
}
printf("get connet:%s\n",inet_ntoa(c_addr.sin_addr));//输出客户端的ip地址
if(fork()==0){//利用进程来实现多个while(1)同时进行,不断的进行访问
if(fork()==0){
while(1){
memset(msg,0,128);//初始化数组,使得数组内部的数据清空,避免数据重复
printf("please input: \n");
gets(msg);//输入消息,程序跑起来之后,会堵塞在这里
write(c_fd,msg,strlen(msg));//发送数据给客户端
}
}
while(1){
memset(redbuf,0,128);//和上面类似,清空数据
n_read=read(c_fd,redbuf,128);//将客户端发过来的消息读到redbuf中,并返回字节数
if(n_read==-1){
perror("read");
}else{
printf("get messgae:%d,%s\n",n_read,redbuf);//输出收到的消息
}
}
break;
}
}
return 0;
}
2.客户端的实现
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
int main(int argc,char **argv)//给main赋参数,以使得自身能自由输入ip地址和端口号
{
struct sockaddr_in c_addr;
int len;
int c_fd;
int nread;
char redbuf[128]={0};
char msg[128]={0};
if(argc!=3){
printf("put error\n");
exit(-1);
}
len=sizeof(struct sockaddr);
memset(&c_addr,0,sizeof(struct sockaddr_in));
c_fd=socket(AF_INET,SOCK_STREAM,0);
if(c_fd==-1)
{
perror("socket");
exit(-1);
}
c_addr.sin_family=AF_INET;
c_addr.sin_port=htons(atoi(argv[2]));
inet_aton(argv[1],&c_addr.sin_addr);
if(connect(c_fd,(struct sockaddr *)&c_addr,len)==-1){//客户端,只连接一次就可以了
perror("connect");
exit(-1);
}
while(1){//利用死循环使得客户端能与服务端不断进行数据的交互
if(fork()==0){
while(1){
memset(msg,0,sizeof(msg));//清空数据,防止消息堆积
printf("please input: \n");
gets(msg);
write(c_fd,msg,strlen(msg));//发送消息给服务端
}
}
while(1){
memset(redbuf,0,sizeof(redbuf));//清空数据
nread=read(c_fd,redbuf,128);//将服务端发送过来的消息读到redbuf里面去
if(nread==-1){
perror("read");
}else{
printf("get message from server:%d,%s\n",nread,redbuf);//打印消息
}
}
}
return 0;
}
三、实现两个端口的通信(类似于qq聊天)
1.程序的编译
首先将服务端和客户端的代码放入liunx系统中
然后开始编译
依次输入
gcc server.c -o server
gcc client.c -o client
有一些警告,但这不影响编译的运行,可以忽略
然后我们得到两个可执行程序
2.运行服务端和客服端
先运行服务端输入
./server 127.0.0.1 8888
博主就直接在一台虚拟机上运行看看实际效果了,我们再开一个终端然后输入
./client 127.0.0.1 8888
然后我们看看运行效果
可以看到我们成功的实现了两个窗口聊天,当然在不同设备上也能实现,只要ip地址和端口号能对上就可以。
总结
socket网络编程的功能十分强大,我们还可以利用它做更多的事,博主也只是在这里做了一个很小的demo。