https://www.write-bug.com/article/1274.html
一 需求分析
柏克莱套接字,又称为BSD 套接字是一种应用程序接口,用于网际插座与Unix域套接字,包括了一个用C语言写成的应用程序开发库,主要用于实现进程间通讯,在计算机网络通讯方面被广泛使用。
使用Berkeley套接字的系统有很多,本系统是在Ubuntu下用C语言进行socket编程。
二 程序设计
2.1 系统流程设计
如下图所示:
2.2 数据结构设计
socket编程问题中涉及的数据结构包括 套接口地址结等。
为了实现这些数据结构,用C语言定义变量如下:
structsockaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
};
三 程序实现
3.1 TCP通信流程
如下图所示:
3.2 实现技术
为实现上述设计,采用C语言,gcc4.9.2 + Vim开发环境。具体采用的技术如下:
socket()函数 int socket(int domain, int type, int protocol);
bind()函数 intbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
listen()函数 int listen(int sockfd, int backlog);
connect()函数 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
accept()函数 int accept(int sockfd, struct sockaddr addr, socklen_t addrlen);
close()函数 int close(int fd);
实现步骤如下:
gcc -o server server.c
gcc -o client client.c
./server
./client
3.3 关键代码说明
为了进一步了解操作系统内核,学习了Linux操作系统的进程同步程序,主要程序源代码如下:
-----------------------client.c---------------------
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#define MYPORT 8887
#define BUFFER_SIZE 1024
int main() {
///定义sockfd
int sock_cli = socket(AF_INET,SOCK_STREAM, 0);
///定义sockaddr_in
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(MYPORT); ///服务器端口
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); ///服务器ip
///连接服务器,成功返回0,错误返回-1
if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("connect");
exit(1);
}
char sendbuf[BUFFER_SIZE];
char recvbuf[BUFFER_SIZE];
memset(recvbuf, '\0', sizeof(recvbuf));
while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL) {
send(sock_cli, sendbuf, strlen(sendbuf),0); ///发送
if(strcmp(sendbuf,"q\n")==0)
break;
recv(sock_cli, recvbuf, sizeof(recvbuf),0); ///接收
fputs(recvbuf, stdout);
memset(sendbuf, 0, sizeof(sendbuf));
memset(recvbuf, 0, sizeof(recvbuf));
}
close(sock_cli);
return 0;
}
-----------------------server.c-----------------------
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#define MYPORT 8887
#define QUEUE 20
#define BUFFER_SIZE 1024
char ans[BUFFER_SIZE];
void _itoa(int n) {
char ans2[BUFFER_SIZE];
int l = 0;
while (n) {
ans2[l++] = n % 10 + '0';
n /= 10;
}
int l2 = 0;
while (l) {
ans[l2++] = ans2[--l];
}
ans[l2++] = '\n';
ans[l2] = '\0';
}
int main() {
///定义sockfd
int server_sockfd = socket(AF_INET,SOCK_STREAM, 0);
///定义sockaddr_in
struct sockaddr_in server_sockaddr;
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_port = htons(MYPORT);
server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
///bind,成功返回0,出错返回-1
if(bind(server_sockfd,(struct sockaddr *)&server_sockaddr,sizeof(server_sockaddr))==-1) {
perror("bind");
exit(1);
}
///listen,成功返回0,出错返回-1
if(listen(server_sockfd,QUEUE) == -1) {
perror("listen");
exit(1);
}
///客户端套接字
char buffer[BUFFER_SIZE];
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
///成功返回非负描述字,出错返回-1
int conn = accept(server_sockfd, (struct sockaddr*)&client_addr, &length);
if(conn<0) {
perror("connect");
exit(1);
}
while(1) {
memset(buffer,0,sizeof(buffer));
int len = recv(conn, buffer, sizeof(buffer),0);
if(strcmp(buffer,"q\n")==0)
break;
int a = 0;
int i, blen = strlen(buffer);
for (i = 2; i < blen - 1; i++) {
if (buffer[i] != ',') {
a = a * 10 + buffer[i] - '0';
} else {
i++;
break;
}
}
int b = 0;
for (; i < blen - 1; i++) {
b = b * 10 + buffer[i] - '0';
}
_itoa(a+b);
fputs(buffer, stdout);
send(conn, ans, strlen(ans), 0);
}
close(conn);
close(server_sockfd);
return 0;
}
这一段程序的主要功能为:
向server发送要计算的表达式并接收计算结果
接收client发送的表达式并计算,在终端输出表达式并把计算结果发回到client
四 运行测试
例如,客户端输入+,100,200,根据分析,运行结果应为:300
实际运行结果如下: