clien.c
#include //printf,sprintf,perror 相关声明在此文件中
#include //memset,strlen
#include //close
#include //sockaddr_in,socket,AF_INET,SOCK_STREAM,htons,inet_addr,connect,sockaddr,send,recv //相关定义和声明在此文件中
#define MAX_CONN 2
#define BUF_SIZE 1024
#define PORT 9000
int main(int argc, char *argv[])
{
printf("argc is %d \n", argc);
int i;
for (i = 0; i<argc; i++)
{
printf("arcv[%d] is %s\n", i, argv[i]);
}
struct sockaddr_in server_sai;
int sfd = 0, res = -1, recvbytes = 0, sendbytes = 0;
char buf[BUF_SIZE], buf2[5] = {0}; // 进行变量的定义和初始化
if (argc < 3) // 如果参数小于3个就报错,命令后面会分别加上IP地址和消息内容,所以一共是三个参数
{
printf("error number of argc:%d\n", argc);
return res;
}
memset(buf, 0, sizeof(buf)); // 对buf清零
sprintf(buf, "%s", argv[2]); // 将要传输的内容(第二个参数)复制到buf中
if (-1 == (sfd = socket(AF_INET, SOCK_STREAM, 0))) // 创建一个IPV4的TCP socket
{
perror("socket");
return res;
}
server_sai.sin_family = AF_INET; // IPV4 协议族
server_sai.sin_port = htons(PORT); // 9000端口
server_sai.sin_addr.s_addr = inet_addr(argv[1]); // 使用第一个参数作为IP地址
memset(&(server_sai.sin_zero), 0, sizeof(server_sai.sin_zero)); // 将结构体剩余部分填零
if (-1 == connect(sfd, (struct sockaddr *)&server_sai, sizeof(struct sockaddr))) // 使用sfd进行连接
{
perror("connect");
return res;
}
if (-1 == (sendbytes = send(sfd, buf, strlen(buf), 0))) // 将buf中的内容写到远端服务端,buf中的内容是命令行中的第二个参数
{
perror("send");
return res;
}
recvbytes = recv(sfd, buf2, 5, 0); // 从服务端接收数据,写到buf2中
printf("%d -->%s\n", recvbytes, buf2); // 将buf2中的数据显示出来
close(sfd); // 进行清理工作,关闭描述符
res = 0;
return res;
}
server.c
#include //perror,printf 相关函数在此声明
#include //sockaddr_in,htons,htonl,socket,AF_INET,SOCK_STREAM,INADDR_ANY,SOL_SOCKET,SO_REUSEADDR,bind,listen,accept,recv,send 相关声明和定义在这个文件中
#include //memset 相关函数在此声明
#include //close 相关函数在此声明
#define MAX_CONN 2
#define BUF_SIZE 1024
#define PORT 9000
int main()
{
struct sockaddr_in server_sai, client_sai;
int sfd = 0, cfd = 0, res = -1, on = 1, recvbytes = 0, sendbytes = 0;
int addrlen = sizeof(struct sockaddr);
char buf[BUF_SIZE]; // 各种变量定义与初始化
if (-1 == (sfd = socket(AF_INET, SOCK_STREAM, 0))) // 创建一个IPV4的TCP socket
{
perror("socket");
return res;
}
server_sai.sin_family = AF_INET; // IPV4 协议族
server_sai.sin_port = htons(PORT); // 9000端口
server_sai.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0 的通配监听
memset(&(server_sai.sin_zero), 0, sizeof(server_sai.sin_zero)); // 将剩余部分填零
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); // closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket
if (-1 == bind(sfd, (struct sockaddr *)&server_sai, sizeof(struct sockaddr))) // 将 sfd 和 socket 地址进行绑定
{
perror("bind");
return res;
}
if (-1 == (listen(sfd, MAX_CONN))) // 在sfd上进行监听,最多允许同时有2个请求在队列中排队,此配置正是DDOS的攻击点,协议天然的缺陷在于,不论这个值设多设少,都不会是一个适合的值
{
perror("listen");
return res;
}
else
printf("Listening...\n");
if (-1 == (cfd = accept(sfd, (struct sockaddr *)&client_sai, (socklen_t *)&addrlen))) // 接受连接,将返回的描述符赋给cfd
{
perror("accept");
return res;
}
memset(buf, 0, sizeof(buf)); // 将缓存置零
if (-1 == (recvbytes = recv(cfd, buf, BUF_SIZE, 0))) // 从对端接受内容并且存到buf中
{
perror("recv");
return res;
}
printf("Received a message:%s\n", buf); // 将收到的内容输出
if (-1 == (sendbytes = send(cfd, "OK", 2, 0))) // 给客户端回复一个ok
{
perror("send");
return res;
}
close(sfd);
close(cfd); // 进行清理,关闭打开的描述符
res = 0;
return res;
}
clien.cpp
#include
#include
#include
#include
#include
#include
int main(){
//创建套接字
int sock = socket(AF_INET, SOCK_STREAM, 0);
//向服务器(特定的IP和端口)发起请求
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
serv_addr.sin_port = htons(1234); //端口
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//读取服务器传回的数据
char buffer[40];
read(sock, buffer, sizeof(buffer)-1);
printf("Message form server: %s\n", buffer);
//关闭套接字
close(sock);
return 0;
}
server.cpp
#include
#include
#include
#include
#include
#include
#include
#include
int main(){
//创建套接字
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//将套接字和IP、端口绑定
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
serv_addr.sin_port = htons(1234); //端口
bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//进入监听状态,等待用户发起请求
listen(serv_sock, 20);
//接收客户端请求
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size = sizeof(clnt_addr);
int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
// 打印收到的客户端地址端口信息
std::cout << "Client address: " << inet_ntoa(clnt_addr.sin_addr) << ", port: " << ntohs(clnt_addr.sin_port) << std::endl;
//向客户端发送数据
char str[] = "http://c.biancheng.net/socket/";
write(clnt_sock, str, sizeof(str));
//关闭套接字
close(clnt_sock);
close(serv_sock);
return 0;
}
服务端持续接收客户端请求,其实就是加了个while循环
#include
#include
#include
#include
#include
#include
#include
#include
int main() {
//创建套接字
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//将套接字和IP、端口绑定
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址
serv_addr.sin_port = htons(1234); //端口
bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
//进入监听状态,等待用户发起请求
listen(serv_sock, 20);
while (true) {
//接收客户端请求
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size = sizeof(clnt_addr);
int clnt_sock =
accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_addr_size);
// 打印收到的客户端地址端口信息
std::cout << "Client address: " << inet_ntoa(clnt_addr.sin_addr)
<< ", port: " << ntohs(clnt_addr.sin_port) << std::endl;
//向客户端发送数据
char str[] = "http://c.biancheng.net/socket/";
write(clnt_sock, str, sizeof(str));
//关闭套接字
close(clnt_sock);
}
close(serv_sock);
return 0;
}