server服务器端的实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <arpa/inet.h>
#define PORT 9527
#define MAXNUM 128
#include <ctype.h>
void sys_error(const char *str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
int lfd, sfd; // 2个套接字(监听 + 通信)
int ret;
int n; // 读的字节数
// 1、socket()监听专用套接字
lfd = socket(AF_INET, SOCK_STREAM, 0); // 采用ipv4 流式协议的典型协议TCP
if (lfd == -1)
sys_error("server socket error");
// 2、bind()绑定服务器自己的sockaddr地址结构(ip + 端口号)
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(PORT);
saddr.sin_addr.s_addr = htonl(INADDR_ANY); // INADDR_ANY获取本机可用的ip地址(本地字节序)
ret = bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));
if (ret == -1)
sys_error("server bind error");
// 3、设置监听上限
ret = listen(lfd, MAXNUM);
if (ret == -1)
sys_error("server listen error");
// 4、阻塞等待客户端建立连接--建立连接并新建1个通信专用socket
struct sockaddr_in caddr; // 用来接收客户端的地址结构
socklen_t caddrlen = sizeof(caddr);
while (1) // 一直等待客户端连接
{
sfd = accept(lfd, (struct sockaddr *)&caddr, &caddrlen);
if (sfd == -1)
sys_error("server accept error");
// 打印与服务器建立连接的客户端的地址结构(网络字节序下的(二进制的整数))
char cip[50];
inet_ntop(AF_INET, (void *)&caddr.sin_addr.s_addr, cip, sizeof(cip));
printf("客户端ip地址: %s\n", cip);
printf("客户端端口号: %u\n", ntohs(caddr.sin_port));
// 5、读客户端发的数据
char buf[BUFSIZ]; // 接收读到的数据
while ((n = read(sfd, buf, BUFSIZ)) != 0)
{
// 打印到屏幕上
printf("客户端发来的数据: %s", buf);
// 转大写
for (int i = 0; i < n; ++i)
buf[i] = toupper(buf[i]);
// 6、写给客户端
ret = write(sfd, buf, n);
if (ret == -1)
sys_error("server write error");
}
// 7、读客户端的数据完毕--断开连接
ret = close(sfd);
if (ret == -1)
sys_error("server close error");
}
return 0;
}
client客户端的实现 -隐式绑定
系统帮忙分配本机可用ip和随机的一个端口号
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <arpa/inet.h>
#define PORT 9527 // 这是服务器端的端口号
void sys_error(const char *str)
{
perror(str);
exit(1);
}
int main(int argc, char *argv[])
{
int cfd; // 客户端的通信套接字
int ret;
int n; // 读到的字节数
// 1、socket()建立通信套接字
cfd = socket(AF_INET, SOCK_STREAM, 0); // ipv4 采用流式协议的典型协议TCP
if (cfd == -1)
sys_error("client error");
// 客户端不bind()
// 系统帮忙隐式绑定sockaddr地址结构(ip + 端口号)
// 客户端的ip + 端口号都是系统帮忙分配的
// 2、connect()连接到服务器
struct sockaddr_in saddr; // 服务器的地址结构 ip + 端口号
socklen_t saddrlen = sizeof(saddr);
saddr.sin_family = AF_INET;
saddr.sin_port = htons(PORT); // 网络字节序下的端口号
uint32_t Ip;
ret = inet_pton(AF_INET, argv[1], (void *)&Ip);
if (ret == 0)
sys_error("client inet_pton invaild");
else if (ret == -1)
sys_error("client inet_pton error");
saddr.sin_addr.s_addr = Ip; // 网络字节序下的ip地址
ret = connect(cfd, (struct sockaddr *)&saddr, saddrlen);
if (ret == -1)
sys_error("client connect error");
char buf[BUFSIZ]; // 用来接收从键盘获取的数据
while ((n = read(STDIN_FILENO, buf, BUFSIZ)) != 0)
{
// 3、写数据
ret = write(cfd, buf, n);
if (ret == -1)
sys_error("client write error");
// 4、读数据
ret = read(cfd, buf, BUFSIZ);
if (ret == -1)
sys_error("client read error");
// 打印到屏幕上
printf("从服务器端接收到的数据: %s", buf);
}
ret = close(cfd);
if (ret == -1)
sys_error("client close error");
return 0;
}
只写服务器端程序, 可以利用nc命令简单测试 nc IP地址 端口号
nc 127.0.0.1 9527