ser.c:
#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<string.h>
int main()
{
int sockSer = socket(AF_INET, SOCK_STREAM, 0);// 创建套接字
if(sockSer == -1)// 出错处理
{
perror("socket.");
exit(1);
}
struct sockaddr_in addrSer ,addrCli;// 服务端和客户端的套接字地址结构体
addrSer.sin_family = AF_INET;// 设置服务器端使用Ipv4
addrSer.sin_port = htons(8080);// 设置服务器端端口为8080
addrSer.sin_addr.s_addr = inet_addr("127.0.0.1");// 设置服务器端的Ip地址为本地环回地址
socklen_t addrlen = sizeof(struct sockaddr); // 套接字地址结构体的大小
int ret = bind(sockSer,(struct sockaddr*)&addrSer,addrlen);// 绑定套接字
if(ret == -1)
{
close(sockSer);
perror("bind.");
exit(1);
}
int ret_l = listen(sockSer, 5);// 设置监听,最大连接数为5
if(ret_l == -1)
{
close(sockSer);
perror("listen.");
exit(1);
}
int sockConn = accept(sockSer,(struct sockaddr*)&addrCli, &addrlen);// 服务器等待连接
if(sockConn == -1)
{
printf("Server Accept Client Connect Fail.\n");
}
else
printf("Server Accept Client Connect Success.\n");
char sendbuf[256];
char recvbuf[256];
while(1)
{
// 客户端和服务器通信的方式是一问一答的方式。应注意避免发生阻塞
printf("Ser:>");
scanf("%s",sendbuf);
send(sockConn, sendbuf, strlen(sendbuf)+1,0);// 通过sockConn套接字来发送、接收数据
recv(sockConn, recvbuf, 256, 0);
printf("Cli:>%s\n",recvbuf);
}
close(sockSer);// 关闭sockSer套接字
}
ser.c里面用到的Linux接口函数(API)
socket()--创建套接字,parameter1:使用的协议;parameter2:通信的类型;parameter3:一般为0,用于选择parameter2中的特定类型
htons()--将无符号的短整数(端口号)从本地字节序换为网络字节序
inet_addr()--将网络主机地址从Ipv4的点分十进制转换为网络字节序的二进制数据。若输入无效返回-1,但-1是有效地址(255.255.255.255)建议使用inet_aton()输入有效返回非零值,输入无效返回0
bind()--将一个名字和一个套接字绑定到一起,为套接字分配一个本地地址
listen()--在一个套接字上监听连接,并指定监听队列的数目
accept()--在一个套接字上接收连接,第一个参数为socket()创建,并设置过listen()监听的套接字。第二个参数为连接实体填充的套接字地址结构,第三个参数为第二个参数结构体的大小。套接字为阻塞的话,acceppt()将一直等待,直到有连接到达;套接字为非阻塞的话,返回EAGIN
send()--从套接字发送信息,当要发送的消息长度大于套接字当前可用缓冲区时,send 将阻塞,除非在套接字上设置了非阻塞式输入输出模式.对于非阻塞模式,这种情况下将返回 EAGAIN 错误
recv()--从connect套接字接收信息。
cli.c:
#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<netinet/in.h>
int main()
{
int sockCli = socket(AF_INET, SOCK_STREAM, 0);// 客户端这边也需要创建套接字?
if(sockCli == -1)
{
perror("socket.");
exit(1);
}
// 服务器端的套接字地址结构体
struct sockaddr_in addrSer;
addrSer.sin_family =AF_INET;
addrSer.sin_port = htons(8080);
addrSer.sin_addr.s_addr = inet_addr("127.0.0.1");
socklen_t addrlen = sizeof(struct sockaddr);
int ret = connect(sockCli,(struct sockaddr*)&addrSer, addrlen);
if(ret == -1)
{
printf("Client connect server fail.");
close(sockCli);
exit(1);
}
else
{
printf("Client connect server success.");
}
char sendbuf[256];
char recvbuf[256];
while(1)
{
recv(sockCli,recvbuf,256,0);//客户端收发都是通过sockCli套接字
printf("Ser:>%s\n",recvbuf);
printf("Cli:>");
scanf("%s",sendbuf);
send(sockCli, sendbuf, strlen(sendbuf)+1,0);
}
close(sockCli);
return 0;
}
cli.c里面用到的Linux接口函数(API)
connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
系统调用将文件描述符sockfd引用的套接字连接到addr指定的地址。addrlen参数指定addr的大小。addr中地址的格式由套接字sockfd的地址空间确定。通常,基于连接的协议套接字只能成功一次connect();无连接协议套接字可以多次使用connect()来更改其关联。无连接套接字可以通过连接到地址并将sockaddr的sa_family成员设置为AF_UNSPEC(从内核2.2开始受Linux支持)来解除关联。