一、服务器端的搭建Server:
1流程socket()--->struct sockaddr_in; ----->bind()------>listen() ---->accept()----->recv()/send()----->close();
2.编写服务器重点函数用法:
a. socket()
#include<sys/socket.h>
int socket(int family, int type, int protocol );
return: 成功返回非负描述符(也叫套接字描述符,简称sockfd),失败返回-1;
family 是协议族(AF_INET是Ipv4的协议,还有ipv6,unix);type是指明套接字类型(SOCK_STREAM,SOCK_DGRAM,流式套接字,数据报套接字);protocol 一般置0,选择所给定family和type组合的系统默认值.
绑定之前用地址结构填充套接字:
struct sockaddr_in addrSer,addrCli;
addSer.sin_family = AF_INET;
addSer.sin_port = htons(MY_PORT);//其中htons()将主机字节顺序转换成网络字节顺序的短整型,属于大端模式
addSer.sin_addr.s_addr = inet_addr(IP_SER);//其中inet_addr()是将带小数点和十进制数转换成二进制以便计算机读取。
socklen_t len = sizeof(struct sockaddr_in);//返回socklen_t类型的len
inet_addr()头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
b.bind()
#include<sys/socket.h>
int bind(int socket, const struct sockaddr *address,socklen_t address_len);
return 成功0,失败返回-1;
第一个参数:套接字描述符,创建的套接字返回值。
第二个参数:const struct sockadr*address: 指向特定于协议的地址结构的指针,若定义的是struct sockaddr_in需要强制类型转换。
第三个参数:返回一个socklen_t类型的该地址结构的长度,(其中socklen_t可以等价short类型,struct sockaddr和struct sockaddr_in的长度都是16字节)。
c.listen()
listen函数使用主动连接套接字变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。
该函数把创建的时的socket<主动套接字>,当调用connect时候发起连接客户端套接字,listen把主动套接字变为被动套接字
#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd, int backlog);
return 成功返回0,失败返回-1;
第一个参数:套接字描述符,创建的套接字返回值。
第二个参数:监听套接字消息队列最大值(5~10)
d.accept()
#include <sys/socket.h>
int accept(int socket, struct sockaddr *restrictaddress, socklen_t *restrict address_len);
return :成功返回非负套接字(既创建了新的套接字,返回一个全新的套接字描述符(已连接套接字描述符)),失败-1;
int sockConn = accept(sockSer,(struct sockaddr*)&addrCli,&len)
第一个参数:监听套接字由socket创建
第二个参数:指向cliaddr结构的指针,指向的是特定协议的地址结构的指针,由于返回类型是标准的地址结构的指 针所以,需要强制类型转换(struct sockaddr*)(注意这里指向的是客户端的地址结构指针)
第三个参数:指向len的指针,地址就是指针。
e.recv()/send()服务器一般先打开,等待客户端的连接,所以一般先接消息再发消息。
recv()
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
第一个参数:是已连接套接字(即新的sockConn套接字描述符)。
第二个参数: buf的地址,由于数组名就是地址所以直接写出地址。
第三个地址: 一般0,默认的普通接受数据模式。
send()
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
第一个参数:是已连接套接字(即新的sockConn套接字描述符)。
第二个参数: buf的地址,由于数组名就是地址所以直接写出地址。
第三个地址: 一般0,默认的普通发送数据模式。
char sendbuf[256];
char recvbuf[256];
while(1)
{
recv(sockConn,recvbuf,256,0);
printf("Cli : %s\n",recvbuf);
printf("Ser : ");
scanf("%d",sendbuf);要发的消息不能加\n;
if(strcmp(sendbuf, "quit") == 0)
break;
sendbuf(sockConn, sendbuf,strlen(sendbuf)+1,0);
}
总结:recv(),send() 函数,要是先接受就要先写recv()函数,,下一行用printf函数输出接收函数的字符串,
要是send()函数,发送函数,先布置好格式,用scanf()函数输入发送的字符串,最后在调用send(即可
发送字符串。
recv();接受函数先接再写,用printf("%s\n",recvbuf)函数加\n输出,可以一句输出结束。
send();发送函数先写再发,用scanf("%s",sendbuf)函数不加\n输入,分多句完成。
f.close()
#include <unistd.h>
int close(int fd);
头文件:
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/socket.h>
4 #include<stdlib.h>
5 #include<string.h>
6 #include<netinet/in.h>
7 #include<arpa/inet.h>
8
9 #define MY_PORT 9080
10 #define IP_ADDR "127.0.0.1"
11 #define LISTEN_QUENE_SIZE 5
12 #define MAX_BUFFER_SIZE 256
搭建服务器代码:
1 #include"utitl.h"
2 //Server()
3 int main()
4 {
5 //socket()
6 int sockSer = socket(AF_INET, SOCK_STREAM, 0);
7 if(sockSer == -1)
8 {
9 perror("Ser socket");
10 exit(1);
11 }
12 struct sockaddr_in addrSer,addrCli;
13 addrSer.sin_family = AF_INET;
14 addrSer.sin_port = htons(MY_PORT);
15 addrSer.sin_addr.s_addr = inet_addr(IP_ADDR);
16 //bind()
17 int len = sizeof(struct sockaddr_in);
18 int Bind_Ser = bind(sockSer, (struct sockaddr*)&addrSer, len);
19 if (Bind_Ser == -1)
20 {
21 perror("Ser bind");
22 exit (1);
23 }
24 //listen()
25 int Listen_Ser = listen(sockSer,LISTEN_QUENE_SIZE);
26 if(Listen_Ser == -1)
27 {
28 perror("Ser listen");
29 exit(1);
30 }
31 //accept()
32 int sockConn = accept(sockSer, (struct sockaddr*)&addrCli,&len);
33 if(sockConn == -1)
34 {
35 printf("Server accept client is failuer.\n");
36 close(sockSer);
37 exit(1);
38 }
39 else
40 {
41 printf("Server accept client is ok.\n");
42 }
43 char sendbuf[MAX_BUFFER_SIZE];
44 char recvbuf[MAX_BUFFER_SIZE];
45 //recv(), send()
46 while (1)
47 {
48 recv(sockConn,recvbuf,MAX_BUFFER_SIZE,0);
49 printf("Cli : >%s\n",recvbuf);
50 printf("Ser : >");
51 scanf("%s",sendbuf);
52 if(strcmp(sendbuf,"quit") == 0)
53 break;
54 send(sockConn,sendbuf,strlen(sendbuf)+1,0);
55 }
56 close(sockSer);
57 return 0;
58 }
:
1.流程 socket()--->struct sockaddr_in(addrSer)(bind())--->connect()---->send()/recv()---->close();
2.编写客户端函数重点:
注意:客户端可以不绑定套接字,listen()函数是服务器特有函数函数。
connect()创建的第二个参数需要服务器的地址结构,所以要构建服务器的地址结构addrSer,第三个参数求的是地址 结构的长度。
3.connect()
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
第一个参数:是客户端套接字描述符sockCli
第二个参数: 是指向特定的协议地址结构指针&addrSer
第三个参数:返回值为socklen_t的地址结构长度。
return :成功返回0.失败-1
服务器代码:
1 #include"utitl.h"
2 //Client
3 int main()
4 {
5 //socket()
6 int sockCli = socket(AF_INET, SOCK_STREAM, 0);
7 if(sockCli == -1)
8 {
9 perror("Cli socket");
10 exit(1);
11 }
12 struct sockaddr_in addrSer;
13 addrSer.sin_family = AF_INET;
14 addrSer.sin_port = htons(MY_PORT);
15 addrSer.sin_addr.s_addr = inet_addr(IP_ADDR);
16 socklen_t len = sizeof( struct sockaddr );
17 //connect()
18 int sockConn = connect(sockCli, (struct sockaddr *)&addrSer, len);
19 if(sockConn == -1)
20 {
21 printf("Client connect server is failuer .\n");
22 close(sockCli);
23 exit(1);
24 }
25 else
26 {
27 printf("Client connect server is ok.\n");
28
29 }
30 char sendbuf[MAX_BUFFER_SIZE];
31 char recvbuf[MAX_BUFFER_SIZE];
32 // send(), recv();
33 while(1)
34 {
35 printf("Cli : >");
36 scanf("%s",sendbuf);
37 if(strcmp(sendbuf,"quit") == 0)
38 break;
39 send(sockCli,sendbuf,strlen(sendbuf)+1,0);
40
41 recv(sockCli,recvbuf,MAX_BUFFER_SIZE,0);
42 printf("Ser : >%s\n",recvbuf);
43 }
44 close(sockCli);
45
46 return 0;
47 }