刚刚接触到服务器编程的知识,来温习一下,实现最基本的TCP服务器和客户端编程流程
TCP协议是面向连接的、可靠的、字节流服务。
一、创建socket
服务器基本流程:socket、bind、listen、accept、recv/send、close
客户端基本流程:socket、connect、send/recv、close
#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain, int type, int protocol);
domain:告诉系统使用哪个底层协议族。对TCP/IP协议族而言,该参数应该设置为PF_INET(IPv4)或PF_INET6(IPv6)。对于UNIX本地域协议族而言,该参数应该设置为PF_UNIX.
type:指定服务类型。服务类型主要有SOCK_STREAM服务(流服务)和SOCK_DGRAM(数据报)服务。对于TCP/IP协议族而言,其值取SOCK_STREAM表示传输层使用TCP协议,取SOCK_DGRAM表示传输层使用UDP协议。
protocol:在前两个参数构成的协议集合下,再选择一个具体的协议。不过这个值通常都是唯一的(前两个参数通常已经确定了具体的协议)。所以几乎在所有的情况下,都把它设置为0,表示使用默认协议。
二、绑定(IP地址+端口号)
int bind(int sockfd, struct sockaddr *seraddr, int len);
struct sockaddr_in
{
sa_family_t sin_family; //协议族
u_int16_t sin_port; //端口号
struct in_addr sin_addr; //IP地址
};
struct in_addr
{
u_int32_t s_addr;
};
这里注意网络中字节序都是大端模式,一般都需要进行转化!
三、启动监听
int listen(int sockfd, int size);
size:监听队列的大小。两个队列(已完成连接的队列 + 1(正在完成连接的队列))
四、连接客户端
int accept(int sockfd, struct sockaddr *cliaddr, int *len);
返回值:返回本次连接的描述符sockfd
五、连接服务器
int connect(int sockfd, (struct sockaddr *)&seraddr, int len);
六、测试
服务器端:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
int sockfd = socket(PF_INET, SOCK_STREAM, 0); //创建套接字
assert(sockfd != -1); //sockfd相当于描述符
struct sockaddr_in ser, cli;
memset(&ser, 0, sizeof(ser));
ser.sin_family = PF_INET; //协议族
ser.sin_port = htons(6000); //端口号
ser.sin_addr.s_addr = inet_addr("127.0.0.1"); //IP地址 //回环地址
int res = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser)); //绑定
assert(res != -1);
listen(sockfd, 5); //启动监听
while(1) //服务器与客户端多次通讯
{
int len = sizeof(cli);
int c = accept(sockfd, (struct sockaddr *)&cli, &len); //返回本次连接到sockfd
if(c < 0)
continue;
while(1) //接受客户端发来的数据块
{
char recvbuf[128] = {0};
int n = recv(c, recvbuf, 127, 0);
if(n <= 0)
{
printf("one client break!\n");
break;
}
printf("%d %s\n",c, recvbuf);
send(c, "ok", 2, 0);
}
close(c); //关闭当前客户端的套接字
} //继续循环
close(sockfd); //关闭服务器
return 0;
}
客户端:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
int main()
{
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
assert(sockfd != -1);
struct sockaddr_in ser,cli;
memset(&ser, 0, sizeof(ser));
ser.sin_famliy = PF_INET;
ser.sin_port = htons(6000); //端口号(与服务器匹配)
ser.sin_addr.s_addr = inet_addr("127.0.0.1"); //回环地址
int c = connect(sockfd, (struct sockaddr *)&ser, sizeof(ser)); //向服务器发送连接请求
assert(c != -1);
while(1)
{
char buf[128] = {0};
fgets(buf, 128, stdin);
buf[strlen(buf) - 1] = 0;
send(sockfd, buf, strlen(buf), 0); //发送到服务器
char recvbuf[128] = {0};
recv(sockfd, recvbuf, 127, 0);
printf("%s\n", recvbuf);
if(strcmp(buf, "end") == 0)
break;
}
close(c);
return 0;
}